diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index b1de7a2..0000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,2 +0,0 @@ -github: [laosb] -buy_me_a_coffee: laosb diff --git a/Package.swift b/Package.swift index 5fa902a..f88e851 100644 --- a/Package.swift +++ b/Package.swift @@ -26,6 +26,5 @@ let package = Package( .target( name: "CropImage", dependencies: []) - ], - swiftLanguageVersions: [.version("6"), .v5] + ] ) diff --git a/Sources/CropImage/CropImageView.swift b/Sources/CropImage/CropImageView.swift index 9cd2389..2d6d558 100644 --- a/Sources/CropImage/CropImageView.swift +++ b/Sources/CropImage/CropImageView.swift @@ -19,7 +19,7 @@ public struct CropImageView: View { /// - scale: The scale binding of the image. /// - rotation: The rotation binding of the image. /// - crop: An async function to trigger crop action. Result will be delivered via ``onCrop``. - public typealias ControlClosure = ( + public typealias ControlClosure = ( _ offset: Binding, _ scale: Binding, _ rotation: Binding, @@ -30,7 +30,7 @@ public struct CropImageView: View { /// /// - Parameters: /// - targetSize: The size of the cut hole. - public typealias CutHoleClosure = (_ targetSize: CGSize) -> CutHole + public typealias CutHoleClosure = (_ targetSize: CGSize) -> CutHole /// Errors that could happen during the cropping process. public enum CropError: Error { @@ -66,8 +66,8 @@ public struct CropImageView: View { /// /// The error should be a ``CropError``. public var onCrop: (Result) -> Void - var controls: ControlClosure - var cutHole: CutHoleClosure + var controls: ControlClosure + var cutHole: CutHoleClosure /// Create a ``CropImageView`` with a custom controls view and a custom cut hole. public init( image: PlatformImage, @@ -75,8 +75,8 @@ public struct CropImageView: View { targetScale: CGFloat = 1, fulfillTargetFrame: Bool = true, onCrop: @escaping (Result) -> Void, - @ViewBuilder controls: @escaping ControlClosure, - @ViewBuilder cutHole: @escaping CutHoleClosure + @ViewBuilder controls: @escaping ControlClosure, + @ViewBuilder cutHole: @escaping CutHoleClosure ) { self.image = image self.targetSize = targetSize @@ -92,7 +92,7 @@ public struct CropImageView: View { targetScale: CGFloat = 1, fulfillTargetFrame: Bool = true, onCrop: @escaping (Result) -> Void, - @ViewBuilder controls: @escaping ControlClosure + @ViewBuilder controls: @escaping ControlClosure ) where CutHole == DefaultCutHoleView { self.image = image self.targetSize = targetSize @@ -225,15 +225,15 @@ public struct CropImageView: View { } } -#Preview { +struct CropImageView_Previews: PreviewProvider { struct PreviewView: View { @State private var targetSize: CGSize = .init(width: 100, height: 100) @State private var result: Result? = nil - + var body: some View { VStack { CropImageView( - image: .previewImage, + image: .init(contentsOfFile: "/Users/laosb/Downloads/png.png")!, targetSize: targetSize ) { result = $0 @@ -262,16 +262,18 @@ public struct CropImageView: View { } } header: { Text("Result") } } -#if os(macOS) + #if os(macOS) .formStyle(.grouped) -#endif + #endif } } } - - return PreviewView() -#if os(macOS) - .frame(width: 500) - .frame(minHeight: 600) -#endif + + static var previews: some View { + PreviewView() + #if os(macOS) + .frame(width: 500) + .frame(minHeight: 600) + #endif + } } diff --git a/Sources/CropImage/DefaultCutHoleShape.swift b/Sources/CropImage/DefaultCutHoleShape.swift index 9b55369..3a8c93e 100644 --- a/Sources/CropImage/DefaultCutHoleShape.swift +++ b/Sources/CropImage/DefaultCutHoleShape.swift @@ -44,18 +44,20 @@ struct DefaultCutHoleShape: Shape { } } -#Preview("Default") { - VStack { - DefaultCutHoleShape(size: .init(width: 100, height: 100)) - .fill(style: FillStyle(eoFill: true)) - .foregroundColor(.black.opacity(0.6)) +struct DefaultCutHoleShape_Previews: PreviewProvider { + static var previews: some View { + VStack { + DefaultCutHoleShape(size: .init(width: 100, height: 100)) + .fill(style: FillStyle(eoFill: true)) + .foregroundColor(.black.opacity(0.6)) + } + .previewDisplayName("Default") + VStack { + DefaultCutHoleShape(size: .init(width: 100, height: 100), isCircular: true) + .fill(style: FillStyle(eoFill: true)) + .foregroundColor(.black.opacity(0.6)) + } + .previewDisplayName("Circular") } } -#Preview("Circular") { - VStack { - DefaultCutHoleShape(size: .init(width: 100, height: 100), isCircular: true) - .fill(style: FillStyle(eoFill: true)) - .foregroundColor(.black.opacity(0.6)) - } -} diff --git a/Sources/CropImage/DefaultCutHoleView.swift b/Sources/CropImage/DefaultCutHoleView.swift index e9e8664..9323e7d 100644 --- a/Sources/CropImage/DefaultCutHoleView.swift +++ b/Sources/CropImage/DefaultCutHoleView.swift @@ -61,10 +61,11 @@ public struct DefaultCutHoleView: View { } } -#Preview("Default") { - DefaultCutHoleView(targetSize: .init(width: 100, height: 100)) -} - -#Preview("Circular") { - DefaultCutHoleView(targetSize: .init(width: 100, height: 100), isCircular: true) +struct DefaultCutHoleView_Previews: PreviewProvider { + static var previews: some View { + DefaultCutHoleView(targetSize: .init(width: 100, height: 100)) + .previewDisplayName("Default") + DefaultCutHoleView(targetSize: .init(width: 100, height: 100), isCircular: true) + .previewDisplayName("Circular") + } } diff --git a/Sources/CropImage/PlatformImage.swift b/Sources/CropImage/PlatformImage.swift index ab243b5..831e93b 100644 --- a/Sources/CropImage/PlatformImage.swift +++ b/Sources/CropImage/PlatformImage.swift @@ -13,17 +13,10 @@ import AppKit /// /// On macOS, it's `NSImage` and on iOS/visionOS it's `UIImage`. public typealias PlatformImage = NSImage -extension PlatformImage { - @MainActor static let previewImage: PlatformImage = .init(contentsOf: URL(string: "file:///System/Library/Desktop%20Pictures/Hello%20Metallic%20Blue.heic")!)! -} #else import UIKit /// The image object type, aliased to each platform. /// /// On macOS, it's `NSImage` and on iOS/visionOS it's `UIImage`. public typealias PlatformImage = UIImage -extension PlatformImage { - // This doesn't really work, but at least passes build. - static let previewImage: PlatformImage = .init(contentsOfFile: "/System/Library/Desktop Pictures/Hello Metallic Blue.heic")! -} #endif diff --git a/Sources/CropImage/UnderlyingImageView.swift b/Sources/CropImage/UnderlyingImageView.swift index 882ade4..e49de8a 100644 --- a/Sources/CropImage/UnderlyingImageView.swift +++ b/Sources/CropImage/UnderlyingImageView.swift @@ -25,11 +25,6 @@ struct UnderlyingImageView: View { @State private var tempOffset: CGSize = .zero @State private var tempScale: CGFloat = 1 @State private var tempRotation: Angle = .zero - @State private var scrolling: Bool = false -#if os(macOS) - @State private var hovering: Bool = false - @State private var scrollMonitor: Any? -#endif // When rotated odd multiples of 90 degrees, we need to switch width and height of the image in calculations. var isRotatedOddMultiplesOf90Deg: Bool { @@ -71,15 +66,9 @@ struct UnderlyingImageView: View { clampedOffset.height = clampedOffset.height.clamped(to: yOffsetBounds(at: clampedScale)) if clampedScale != scale || clampedOffset != offset { - if scrolling { + withAnimation(.interactiveSpring()) { scale = clampedScale offset = clampedOffset - scrolling = false - } else { - withAnimation(.interactiveSpring()) { - scale = clampedScale - offset = clampedOffset - } } } } @@ -92,24 +81,6 @@ struct UnderlyingImageView: View { scale = min(widthScale, heightScale) } -#if os(macOS) - private func setupScrollMonitor() { - scrollMonitor = NSEvent.addLocalMonitorForEvents(matching: .scrollWheel) { event in - if hovering { - scrolling = true - scale = scale + event.scrollingDeltaY / 1000 - } - return event - } - } - - private func removeScrollMonitor() { - if let scrollMonitor { - NSEvent.removeMonitor(scrollMonitor) - } - } -#endif - var imageView: Image { #if os(macOS) Image(nsImage: image) @@ -123,14 +94,6 @@ struct UnderlyingImageView: View { .gesture(dragGesture) .gesture(magnificationgesture) .gesture(rotationGesture) -#if os(macOS) - .onAppear { - setupScrollMonitor() - } - .onDisappear { - removeScrollMonitor() - } -#endif } var dragGesture: some Gesture { @@ -185,24 +148,21 @@ struct UnderlyingImageView: View { .onChange(of: rotation) { _ in adjustToFulfillTargetFrame() } -#if os(macOS) - .onHover { hovering = $0 } -#endif } } -#Preview { +struct MoveAndScalableImageView_Previews: PreviewProvider { struct PreviewView: View { @State private var offset: CGSize = .zero @State private var scale: CGFloat = 1 @State private var rotation: Angle = .zero - + var body: some View { UnderlyingImageView( offset: $offset, scale: $scale, rotation: $rotation, - image: .previewImage, + image: .init(contentsOfFile: "/Users/laosb/Downloads/png.png")!, viewSize: .init(width: 200, height: 100), targetSize: .init(width: 100, height: 100), fulfillTargetFrame: true @@ -210,6 +170,8 @@ struct UnderlyingImageView: View { .frame(width: 200, height: 100) } } - - return PreviewView() + + static var previews: some View { + PreviewView() + } }