Skip to content

Commit

Permalink
Upgrade dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
sindresorhus committed Mar 30, 2019
1 parent 3f48bf1 commit 5e1140e
Show file tree
Hide file tree
Showing 6 changed files with 504 additions and 232 deletions.
4 changes: 2 additions & 2 deletions Gifski/Constants.swift
Expand Up @@ -5,6 +5,6 @@ extension NSColor {
}

extension Defaults.Keys {
static let outputQuality = Defaults.Key<Double>("outputQuality", default: 1)
static let successfulConversionsCount = Defaults.Key<Int>("successfulConversionsCount", default: 0)
static let outputQuality = Key<Double>("outputQuality", default: 1)
static let successfulConversionsCount = Key<Int>("successfulConversionsCount", default: 0)
}
94 changes: 92 additions & 2 deletions Gifski/CustomButton.swift
Expand Up @@ -2,6 +2,75 @@ import Cocoa

// TODO(sindresorhus): I plan to extract this into a reusable package when it's more mature.

/**
Convenience class for adding a tracking area to a view.
```
final class HoverView: NSView {
private lazy var trackingArea = TrackingArea(
for: self,
options: [
.mouseEnteredAndExited,
.activeInActiveApp
]
)
override func updateTrackingAreas() {
super.updateTrackingAreas()
trackingArea.update()
}
}
```
*/
final class TrackingArea {
private let view: NSView
private let rect: CGRect
private let options: NSTrackingArea.Options
private var trackingArea: NSTrackingArea?

/**
- Parameters:
- view: The view to add tracking to.
- rect: The area inside the view to track. Defaults to the whole view (`view.bounds`).
*/
init(for view: NSView, rect: CGRect? = nil, options: NSTrackingArea.Options = []) {
self.view = view
self.rect = rect ?? view.bounds
self.options = options
}

/**
Updates the tracking area.
This should be called in your `NSView#updateTrackingAreas()` method.
*/
func update() {
if let oldTrackingArea = trackingArea {
view.removeTrackingArea(oldTrackingArea)
}

let newTrackingArea = NSTrackingArea(
rect: rect,
options: [
.mouseEnteredAndExited,
.activeInActiveApp
],
owner: view,
userInfo: nil
)

view.addTrackingArea(newTrackingArea)
trackingArea = newTrackingArea
}
}

final class AnimationDelegate: NSObject, CAAnimationDelegate {
var didStopHandler: ((Bool) -> Void)?

func animationDidStop(_ animation: CAAnimation, finished flag: Bool) {
didStopHandler?(flag)
}
}

extension CALayer {
// TODO: Find a way to use a strongly-typed KeyPath here.
// TODO: Accept NSColor instead of CGColor.
Expand All @@ -16,8 +85,16 @@ extension CALayer {
animation.duration = duration
animation.fillMode = .forwards
animation.isRemovedOnCompletion = false
add(animation, forKey: keyPath)
setValue(color, forKey: keyPath)
add(animation, forKey: keyPath) { [weak self] _ in
self?.setValue(color, forKey: keyPath)
}
}

func add(_ animation: CAAnimation, forKey key: String?, completion: @escaping ((Bool) -> Void)) {
let animationDelegate = AnimationDelegate()
animationDelegate.didStopHandler = completion
animation.delegate = animationDelegate
add(animation, forKey: key)
}
}

Expand Down Expand Up @@ -212,6 +289,19 @@ open class CustomButton: NSButton {
}
}

private lazy var trackingArea = TrackingArea(
for: self,
options: [
.mouseEnteredAndExited,
.activeInActiveApp
]
)

override open func updateTrackingAreas() {
super.updateTrackingAreas()
trackingArea.update()
}

private func setup() {
wantsLayer = true

Expand Down
2 changes: 1 addition & 1 deletion Gifski/MainWindowController.swift
Expand Up @@ -192,7 +192,7 @@ final class MainWindowController: NSWindowController {

progress = Progress(totalUnitCount: 1)
circularProgress.progressInstance = progress
DockProgress.progress = progress
DockProgress.progressInstance = progress
timeEstimator.progress = progress
timeEstimator.start()

Expand Down
217 changes: 127 additions & 90 deletions Gifski/Vendor/CircularProgress+Util.swift
@@ -1,29 +1,60 @@
import AppKit
import Cocoa

extension NSBezierPath {
static func circle(
radius: Double,
center: CGPoint,
startAngle: Double = 0,
endAngle: Double = 360
) -> Self {
let path = self.init()
path.appendArc(
withCenter: center,
radius: CGFloat(radius),
startAngle: CGFloat(startAngle),
endAngle: CGFloat(endAngle)
extension NSColor {
typealias HSBAColor = (hue: Double, saturation: Double, brightness: Double, alpha: Double)
var hsba: HSBAColor {
var hue: CGFloat = 0
var saturation: CGFloat = 0
var brightness: CGFloat = 0
var alpha: CGFloat = 0
let color = usingColorSpace(.deviceRGB) ?? self
color.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha)
return HSBAColor(Double(hue), Double(saturation), Double(brightness), Double(alpha))
}

/// Adjust color components by ratio.
func adjusting(
hue: Double = 0,
saturation: Double = 0,
brightness: Double = 0,
alpha: Double = 0
) -> NSColor {
let color = hsba
return NSColor(
hue: CGFloat(color.hue * (hue + 1)),
saturation: CGFloat(color.saturation * (saturation + 1)),
brightness: CGFloat(color.brightness * (brightness + 1)),
alpha: CGFloat(color.alpha * (alpha + 1))
)
return path
}
}


extension CALayer {
/// This is required for CALayers that are created independently of a view
func setAutomaticContentsScale() {
contentsScale = NSScreen.main?.backingScaleFactor ?? 2
static func animate(
duration: TimeInterval = 1,
delay: TimeInterval = 0,
timingFunction: CAMediaTimingFunction = .default,
animations: @escaping (() -> Void),
completion: (() -> Void)? = nil
) {
DispatchQueue.main.asyncAfter(duration: delay) {
CATransaction.begin()
CATransaction.setAnimationDuration(duration)
CATransaction.setAnimationTimingFunction(timingFunction)

if let completion = completion {
CATransaction.setCompletionBlock(completion)
}

animations()
CATransaction.commit()
}
}
}


extension CALayer {
/**
Set CALayer properties without the implicit animation
Expand Down Expand Up @@ -56,29 +87,41 @@ extension CALayer {
}
}
}
}

static func animate(
duration: TimeInterval = 1,
delay: TimeInterval = 0,
timingFunction: CAMediaTimingFunction = .default,
animations: @escaping (() -> Void),
completion: (() -> Void)? = nil
) {
DispatchQueue.main.asyncAfter(duration: delay) {
CATransaction.begin()
CATransaction.setAnimationDuration(duration)
CATransaction.setAnimationTimingFunction(timingFunction)

if let completion = completion {
CATransaction.setCompletionBlock(completion)
}
extension CALayer {
/// This is required for CALayers that are created independently of a view
func setAutomaticContentsScale() {
contentsScale = NSScreen.main?.backingScaleFactor ?? 2
}
}

animations()
CATransaction.commit()
}

extension NSFont {
static let helveticaNeueLight = NSFont(name: "HelveticaNeue-Light", size: 0)
}


extension NSBezierPath {
static func circle(
radius: Double,
center: CGPoint,
startAngle: Double = 0,
endAngle: Double = 360
) -> Self {
let path = self.init()
path.appendArc(
withCenter: center,
radius: CGFloat(radius),
startAngle: CGFloat(startAngle),
endAngle: CGFloat(endAngle)
)
return path
}
}


extension CAShapeLayer {
static func circle(radius: Double, center: CGPoint) -> Self {
let layer = self.init()
Expand All @@ -92,35 +135,6 @@ extension CAShapeLayer {
}
}

/**
Shows the indeterminate state, when it's activated.
It draws part of a circle that gets animated into a looping motion around its core.
*/
final class IndeterminateShapeLayer: CAShapeLayer {
convenience init(radius: Double, center: CGPoint) {
self.init()
fillColor = nil
path = NSBezierPath.circle(radius: radius, center: bounds.center, startAngle: 270).cgPath
anchorPoint = CGPoint(x: 0.5, y: 0.5)
position = center
}
}

extension CABasicAnimation {
/// Rotates the element around its center point infinitely.
static var rotate: CABasicAnimation {
let animation = CABasicAnimation(keyPath: #keyPath(CAShapeLayer.transform))
animation.valueFunction = CAValueFunction(name: .rotateZ)
animation.fromValue = 0
animation.toValue = -(Double.pi * 2)
animation.duration = 1
animation.repeatCount = .infinity
animation.timingFunction = CAMediaTimingFunction(name: .linear)

return animation
}
}

extension CATextLayer {
/// Initializer with better defaults
Expand Down Expand Up @@ -148,35 +162,58 @@ extension CATextLayer {
}
}

extension NSFont {
static let helveticaNeueLight = NSFont(name: "HelveticaNeue-Light", size: 0)

final class ProgressCircleShapeLayer: CAShapeLayer {
convenience init(radius: Double, center: CGPoint) {
self.init()
fillColor = nil
lineCap = .round
path = NSBezierPath.progressCircle(radius: radius, center: center).cgPath
strokeEnd = 0
}

var progress: Double {
get {
return Double(strokeEnd)
}
set {
strokeEnd = CGFloat(newValue)
}
}

func resetProgress() {
CALayer.withoutImplicitAnimations {
strokeEnd = 0
}
}
}

extension NSColor {
typealias HSBAColor = (hue: Double, saturation: Double, brightness: Double, alpha: Double)
var hsba: HSBAColor {
var hue: CGFloat = 0
var saturation: CGFloat = 0
var brightness: CGFloat = 0
var alpha: CGFloat = 0
let color = usingColorSpace(.deviceRGB) ?? self
color.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha)
return HSBAColor(Double(hue), Double(saturation), Double(brightness), Double(alpha))
/**
Shows the indeterminate state, when it's activated.
It draws part of a circle that gets animated into a looping motion around its core.
*/
final class IndeterminateShapeLayer: CAShapeLayer {
convenience init(radius: Double, center: CGPoint) {
self.init()
fillColor = nil
path = NSBezierPath.circle(radius: radius, center: bounds.center, startAngle: 270).cgPath
anchorPoint = CGPoint(x: 0.5, y: 0.5)
position = center
}
}

/// Adjust color components by ratio.
func adjusting(
hue: Double = 0,
saturation: Double = 0,
brightness: Double = 0,
alpha: Double = 0
) -> NSColor {
let color = hsba
return NSColor(
hue: CGFloat(color.hue * (hue + 1)),
saturation: CGFloat(color.saturation * (saturation + 1)),
brightness: CGFloat(color.brightness * (brightness + 1)),
alpha: CGFloat(color.alpha * (alpha + 1))
)

extension CABasicAnimation {
/// Rotates the element around its center point infinitely.
static var rotate: CABasicAnimation {
let animation = CABasicAnimation(keyPath: #keyPath(CAShapeLayer.transform))
animation.valueFunction = CAValueFunction(name: .rotateZ)
animation.fromValue = 0
animation.toValue = -(Double.pi * 2)
animation.duration = 1
animation.repeatCount = .infinity
animation.timingFunction = CAMediaTimingFunction(name: .linear)
return animation
}
}

0 comments on commit 5e1140e

Please sign in to comment.