Skip to content

Commit

Permalink
Feature/Simple Color picker (#332)
Browse files Browse the repository at this point in the history
  • Loading branch information
borut-t authored Nov 12, 2024
1 parent 51ec85e commit e59da27
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 17 deletions.
33 changes: 17 additions & 16 deletions Resources/UI/SwiftUI/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,24 @@ A package including components to help you out developing for SwiftUI framework.

### Components

| Views | |
| :--- | :--- |
| [ActionButton](ActionButton) | Generic and customizable CTA button |
| [PhotoPickerView](/Sources/UI/SwiftUI/Views/PhotoPickerView/PhotoPickerView.swift) | Photo and Camera picker view used in combination with `PhotoPickerModifier` |
| [ProfileImageView](ProfileImageView) | Generic and customizable profile image view component |
| [ProgressStyle](/Sources/UI/SwiftUI/Views/ProgressStyle/ProgressStyle.swift) | Customizable ProgressViewStyle |
| [RemoteImage](/Sources/UI/SwiftUI/Views/RemoteImage/RemoteImage.swift) | Fetching remote images using Kingfisher |
| [ScrollViewWithOffset](/Sources/UI/SwiftUI/Views/ScrollViewWithOffset/ScrollViewWithOffset.swift) | ScrollView that expose offset as we scroll |
| Views | Platform | |
| :--- | :--- | :--- |
| [ActionButton](ActionButton) | all | Generic and customizable CTA button |
| [PhotoPickerView](/Sources/UI/SwiftUI/Views/PhotoPickerView/PhotoPickerView.swift) | iOS | Photo and Camera picker view used in combination with `PhotoPickerModifier` |
| [ProfileImageView](ProfileImageView) | all | Generic and customizable profile image view component |
| [ProgressStyle](/Sources/UI/SwiftUI/Views/ProgressStyle/ProgressStyle.swift) | all | Customizable ProgressViewStyle |
| [RemoteImage](/Sources/UI/SwiftUI/Views/RemoteImage/RemoteImage.swift) | all | Fetching remote images using Kingfisher |
| [ScrollViewWithOffset](/Sources/UI/SwiftUI/Views/ScrollViewWithOffset/ScrollViewWithOffset.swift) | all | ScrollView that expose offset as we scroll |
| [SimpleColorPicker](/Sources/UI/SwiftUI/Views/SimpleColorPicker/SimpleColorPicker.swift) | macOS | Wrapper for NSColorWell component |

| View Modifiers | |
| :--- | :--- |
| [MeasureSizeModifier](/Sources/UI/SwiftUI/View%20Modifiers/MeasureSizeModifier.swift) | A modifier to return size of the underlying view |
| [OnFirstAppearModifier](/Sources/UI/SwiftUI/View%20Modifiers/OnFirstAppearModifier.swift) | Similar to the `OnAppear` modifier, but only runs once per view lifecycle |
| [PhotoPickerModifier](/Sources/UI/SwiftUI/View%20Modifiers/PhotoPickerModifier.swift) | Easily add photo or camera picker to the view |
| [PinchToZoomModifier](/Sources/UI/SwiftUI/View%20Modifiers/PinchToZoomModifier.swift) | Pinching and zooming in/out with ease |
| [SquaredModifier](/Sources/UI/SwiftUI/View%20Modifiers/SquaredModifier.swift) | Make given view squared. This is mostly used with images to properly keep the aspect ratio |
| [TextFieldLimitModifer](/Sources/UI/SwiftUI/View%20Modifiers/TextFieldLimitModifer.swift) | This modifier adds an upper bound text length limitation to the TextField |
| View Modifiers | Platform | |
| :--- | :--- | :--- |
| [MeasureSizeModifier](/Sources/UI/SwiftUI/View%20Modifiers/MeasureSizeModifier.swift) | all | A modifier to return size of the underlying view |
| [OnFirstAppearModifier](/Sources/UI/SwiftUI/View%20Modifiers/OnFirstAppearModifier.swift) | all | Similar to the `OnAppear` modifier, but only runs once per view lifecycle |
| [PhotoPickerModifier](/Sources/UI/SwiftUI/View%20Modifiers/PhotoPickerModifier.swift) | iOS | Easily add photo or camera picker to the view |
| [PinchToZoomModifier](/Sources/UI/SwiftUI/View%20Modifiers/PinchToZoomModifier.swift) | iOS | Pinching and zooming in/out with ease |
| [SquaredModifier](/Sources/UI/SwiftUI/View%20Modifiers/SquaredModifier.swift) | all | Make given view squared. This is mostly used with images to properly keep the aspect ratio |
| [TextFieldLimitModifer](/Sources/UI/SwiftUI/View%20Modifiers/TextFieldLimitModifer.swift) | all | This modifier adds an upper bound text length limitation to the TextField |

| Extensions |
| :--- |
Expand Down
1 change: 0 additions & 1 deletion Sources/UI/SwiftUI/Views/ProgressStyle/ProgressStyle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
// Copyright © 2024 Povio Inc. All rights reserved.
//


import SwiftUI

@available(iOS 15.0, *)
Expand Down
79 changes: 79 additions & 0 deletions Sources/UI/SwiftUI/Views/SimpleColorPicker/SimpleColorPicker.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//
// SimpleColorPicker.swift
// PovioKit
//
// Created by Borut Tomazin on 15/08/2024.
// Copyright © 2024 Povio Inc. All rights reserved.
//

#if os(macOS)
import SwiftUI
import Combine

/// SwiftUI wrapper for NSColorWell, allowing the selection of colors with a customizable size.
public struct SimpleColorPicker: NSViewRepresentable {
@Binding var selection: Color
var size: CGSize?

public init(selection: Binding<Color>, size: CGSize? = nil) {
self._selection = selection
self.size = size
}

public func makeNSView(context: Context) -> NSColorWell {
let colorWell: NSColorWell
if #available(macOS 13.0, *) {
colorWell = NSColorWell(style: .minimal)
} else {
colorWell = NSColorWell()
}
colorWell.color = NSColor(selection)

context.coordinator.startObservingColorChange(of: colorWell)

// override the size
if let size {
colorWell.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
colorWell.widthAnchor.constraint(equalToConstant: size.width),
colorWell.heightAnchor.constraint(equalToConstant: size.height)
])
}

return colorWell
}

public func updateNSView(_ nsView: NSColorWell, context: Context) {
context.coordinator.colorDidChange = {
selection = Color(nsColor: $0)
}

// update the size
if let size {
if let widthConstraint = nsView.constraints.first(where: { $0.firstAttribute == .width }) {
widthConstraint.constant = size.width
}
if let heightConstraint = nsView.constraints.first(where: { $0.firstAttribute == .height }) {
heightConstraint.constant = size.height
}
}
}

public func makeCoordinator() -> Coordinator {
Coordinator()
}

@MainActor
public class Coordinator: NSObject {
var colorDidChange: ((NSColor) -> Void)?

private var cancellable: AnyCancellable?

func startObservingColorChange(of colorWell: NSColorWell) {
cancellable = colorWell.publisher(for: \.color).sink { [weak self] in
self?.colorDidChange?($0)
}
}
}
}
#endif

0 comments on commit e59da27

Please sign in to comment.