Skip to content

Commit

Permalink
Update CircularProgress (#63)
Browse files Browse the repository at this point in the history
  • Loading branch information
boyvanamstel authored and sindresorhus committed Mar 5, 2019
1 parent fa31670 commit 7d44af0
Show file tree
Hide file tree
Showing 3 changed files with 292 additions and 114 deletions.
4 changes: 4 additions & 0 deletions Gifski.xcodeproj/project.pbxproj
Expand Up @@ -8,6 +8,7 @@

/* Begin PBXBuildFile section */
5A7524BA20D0862200F12C99 /* libgifski.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A7524B520D085FB00F12C99 /* libgifski.a */; };
B576D25422294F9900A9B75C /* CircularProgress+Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = B576D24F22294F9900A9B75C /* CircularProgress+Util.swift */; };
C2040B8920435871004EE259 /* GifskiWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2040B8820435871004EE259 /* GifskiWrapper.swift */; };
C2AFA91D204FFEFD00FC5A7F /* MainWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2AFA91B204FFEFD00FC5A7F /* MainWindowController.swift */; };
E30557F0207E521F003401A1 /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E30557EF207E521F003401A1 /* Defaults.swift */; };
Expand Down Expand Up @@ -67,6 +68,7 @@

/* Begin PBXFileReference section */
5A7524AD20D085FB00F12C99 /* gifski.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = gifski.xcodeproj; path = "gifski-api/gifski.xcodeproj"; sourceTree = "<group>"; };
B576D24F22294F9900A9B75C /* CircularProgress+Util.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CircularProgress+Util.swift"; sourceTree = "<group>"; };
C2040B8820435871004EE259 /* GifskiWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = GifskiWrapper.swift; sourceTree = "<group>"; usesTabs = 1; };
C2AFA91B204FFEFD00FC5A7F /* MainWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = MainWindowController.swift; sourceTree = "<group>"; usesTabs = 1; };
E30557EF207E521F003401A1 /* Defaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Defaults.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -132,6 +134,7 @@
isa = PBXGroup;
children = (
E317FF122057E24700A80A18 /* CircularProgress.swift */,
B576D24F22294F9900A9B75C /* CircularProgress+Util.swift */,
E317FF1B20583E9800A80A18 /* DockProgress.swift */,
E30557EF207E521F003401A1 /* Defaults.swift */,
);
Expand Down Expand Up @@ -351,6 +354,7 @@
E3CB1DD71F7E4CBC00D79BFC /* VideoDropView.swift in Sources */,
E3A940122182DCE5006981D5 /* CustomButton.swift in Sources */,
E3DF3E88203BD2B900055855 /* SavePanelAccessoryViewController.swift in Sources */,
B576D25422294F9900A9B75C /* CircularProgress+Util.swift in Sources */,
C2AFA91D204FFEFD00FC5A7F /* MainWindowController.swift in Sources */,
E3AE62871E5CD2F300035A2F /* AppDelegate.swift in Sources */,
);
Expand Down
175 changes: 175 additions & 0 deletions Gifski/Vendor/CircularProgress+Util.swift
@@ -0,0 +1,175 @@
import AppKit

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

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

/**
Set CALayer properties without the implicit animation
```
CALayer.withoutImplicitAnimations {
view.layer?.opacity = 0.4
}
```
*/
static func withoutImplicitAnimations(closure: () -> Void) {
CATransaction.begin()
CATransaction.setDisableActions(true)
closure()
CATransaction.commit()
}

/**
Toggle the implicit CALayer animation
Can be useful for text layers
*/
var implicitAnimations: Bool {
get {
return actions == nil
}
set {
if newValue {
actions = nil
} else {
actions = ["contents": NSNull()]
}
}
}

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 CAShapeLayer {
static func circle(radius: Double, center: CGPoint) -> CAShapeLayer {
return CAShapeLayer(path: NSBezierPath.circle(radius: radius, center: center))
}

convenience init(path: NSBezierPath) {
self.init()
self.path = path.cgPath
}
}

/**
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
convenience init(text: String, fontSize: Double? = nil, color: NSColor? = nil) {
self.init()
string = text
if let fontSize = fontSize {
self.fontSize = CGFloat(fontSize)
}
self.color = color
implicitAnimations = false
setAutomaticContentsScale()
}

var color: NSColor? {
get {
guard let color = foregroundColor else {
return nil
}
return NSColor(cgColor: color)
}
set {
foregroundColor = newValue?.cgColor
}
}
}

extension NSFont {
static let helveticaNeueLight = NSFont(name: "HelveticaNeue-Light", size: 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))
}

/// 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))
)
}
}

0 comments on commit 7d44af0

Please sign in to comment.