Circular progress indicator for your macOS app

Overview

CircularProgress

Circular progress indicator for your macOS app

This package is used in production by apps like Gifski and HEIC Converter.

Requirements

  • macOS 10.12+
  • Xcode 12.5+
  • Swift 5.4+

Install

Swift Package Manager

Add https://github.com/sindresorhus/CircularProgress in the “Swift Package Manager” tab in Xcode.

Carthage

github "sindresorhus/CircularProgress"

CocoaPods

pod 'CircularProgressMac'

Usage

Also check out the example app in the Xcode project.

Note: All the properties/methods must be set/called from the main thread.

Manually set the progress

import Cocoa
import CircularProgress

@main
final class AppDelegate: NSObject, NSApplicationDelegate {
	@IBOutlet private var window: NSWindow!

	let circularProgress = CircularProgress(size: 200)

	func applicationDidFinishLaunching(_ notification: Notification) {
		window.contentView!.addSubview(circularProgress)

		foo.onUpdate = { progress in
			self.circularProgress.progress = progress
		}
	}
}

Specify a Progress instance

The given Progress instance is strongly kept alive as long as the CircularProgress instance or until you set .progressInstance = nil.

import Cocoa
import CircularProgress

@main
final class AppDelegate: NSObject, NSApplicationDelegate {
	@IBOutlet private var window: NSWindow!

	let circularProgress = CircularProgress(size: 200)
	let progress = Progress(totalUnitCount: 1)

	func applicationDidFinishLaunching(_ notification: Notification) {
		window.contentView!.addSubview(circularProgress)

		progress?.becomeCurrent(withPendingUnitCount: 1)
		circularProgress.progressInstance = progress
	}
}

Cancel button

If you use the .progress property, you need to opt into the cancel button by setting .isCancellable = true. You can be notified of when the button is clicked by setting the .onCancelled property to a closure.

If you use the .progressInstance property, setting a Progress object that is isCancellable, which is the default, automatically enables the cancel button.

Per default, the cancelled state is indicated by desaturing the current color and reducing the opacity. You can customize this by implementing the .cancelledStateColorHandler callback and returning a color to use for the cancelled state instead. The opacity is not automatically reduced when the callback has been set. To disable the cancelled state visualization entirely, set .visualizeCancelledState to false.

Indeterminate state

Displays a state that indicates that the remaining progress is indeterminate.

Note that the .progress property and .isIndeterminate are not tied together. You'll need to manually set .isIndeterminate = false when progress is being made again.

If you use the .progressInstance property, the isIndeterminate property will automatically be observed. The view will then switch back and forth to the indeterminate state when appropriate.

Hidden progress label

Displays a spinner without a percentage indicator in the center.

This is accomplished by setting the .isLabelHidden property to true. The default state is false (the label is displayed).

API

/**
Color of the circular progress view.

Defaults to the user's accent color. For High Sierra and below it uses a fallback color.
*/
@IBInspectable var color: NSColor = .controlAccentColor

/**
Line width of the circular progress view.
*/
@IBInspectable var lineWidth: CGFloat = 2

/**
Show an animated checkmark instead of `100%`.
*/
@IBInspectable var showCheckmarkAtHundredPercent = true

/**
Hide the progress label.

The property supports KVO.
*/
@IBInspectable var isLabelHidden = true

/**
The progress value in the range `0...1`.

- Note: The value will be clamped to `0...1`.
*/
@IBInspectable var progress: Double = 0

/**
Let a `Progress` instance update the `progress` for you.
*/
var progressInstance: Progress?

/**
Reset the progress back to zero without animating.
*/
func resetProgress() {}

/**
Cancels `Progress` if it's set and prevents further updates.
*/
func cancelProgress() {}

/**
Triggers when the progress was cancelled succesfully.
*/
var onCancelled: (() -> Void)?

/**
Returns whether the progress is finished.

The property supports KVO.
*/
@IBInspectable var isFinished: Bool { get }

/**
If the progress view is cancellable it shows the cancel button.
*/
@IBInspectable var isCancellable: Bool

/**
Make the progress indeterminate.

The property supports KVO.
*/
@IBInspectable var isIndeterminate: Bool

/**
Returns whether the progress has been cancelled.

The property supports KVO.
*/
@IBInspectable var isCancelled: Bool { get }

/**
Determines whether to visualize changing into the cancelled state.
*/
var visualizeCancelledState: Bool = true

/**
Supply the base color to use for displaying the cancelled state.
*/
var cancelledStateColorHandler: ((NSColor) -> NSColor)?

init(frame: CGRect) {}
init?(coder: NSCoder) {}

/**
Initialize the progress view with a width/height of the given `size`.
*/
convenience init(size: Double) {}

Related

Maintainers

Comments
  • Add indeterminate state

    Add indeterminate state

    Added the indeterminate state from Carbonize as mentioned in https://github.com/sindresorhus/CircularProgress/issues/9.

    ~~I need to implement it hiding/showing properly when cancelling the progress, so I marked this as a Draft. (And I wanted to try the new GitHub feature. 🤷‍♂️)~~ All done.


    Fixes #9

    opened by boyvanamstel 23
  • Visualize cancelled state

    Visualize cancelled state

    Defaults to desaturating the progress view when it's cancelled.

    Still need to implement the desaturated color animating the color change.

    Fixes https://github.com/sindresorhus/CircularProgress/issues/6

    opened by boyvanamstel 19
  • Tracking area solution

    Tracking area solution

    Fixes https://github.com/sindresorhus/CircularProgress/issues/17

    Proposal for adding TrackingArea that works with CGPath. Ive used this solution in various projects and I feel its almost optimal. Gets away with not having a tracking area variable but adds a bool flag, which I have yet to be able to remove. More detail about why the different methods and variables exist and how they work in tandem in the code-comments.

    Feel free to make requests:

    • Which Linter style to use, Vanilla swift-lint?
    • I know you like less comments so, tone that down maybe?
    • Abstract it into The CustomButton instead maybe?
    • Clean up the project a bit? It's a bit long in the tooth, IMO some +Extensions would do it good
    • There seems to be some margin inside .bounds, I will add that to the path variable
    • Other?

    I will donate the profits to a charitable case. :)

    • Would be great to wrap this up before 8th of April. 😅 But however long it takes of course.

    IssueHunt Summary

    Referenced issues

    This pull request has been submitted to:


    IssueHunt has been backed by the following sponsors. Become a sponsor

    opened by eonist 14
  • Add ability to cancel the progress

    Add ability to cancel the progress

    Brings over the cancel functionality added to Gifski recently.

    cancel

    I chose to copy over the CustomButton verbatim. Using it here might help fleshing out how it should behave as a standalone component later.

    The cancel button currently only appears when a Progress instance has been set that is isCancellable.

    opened by boyvanamstel 14
  • Add tracking area to custom button

    Add tracking area to custom button

    Resolves https://github.com/sindresorhus/CircularProgress/pull/4#issuecomment-458431791

    We could probably use the tracking area in the CircularProgress view as well, but that would require customizing CustomButton just for this.

    opened by boyvanamstel 5
  • Enforce aspect ratio in Interface Builder

    Enforce aspect ratio in Interface Builder

    Issuehunt badges

    Currently, you're able to set it to 300x100 in Interface Builder, which makes it look broken. Would be nice to enforce aspect ratio of 1:1 using auto layout. According to https://forums.developer.apple.com/thread/4108, it should be possible:

    Currently Interface Builder does not allow overriding the layout interactions of a view via IBDesignable (e.g. overriding the standard resizing behaviors in IB). You should, however, be able to add an aspect ratio constraint to your view in your code and IB's auto layout integration will pick this up and properly size the view whenever you choose the "Update Frames" command in the canvas.

    But I could not get it working.

    How to create aspect ratio constraint: https://stackoverflow.com/questions/31334017/how-can-i-set-aspect-ratio-constraints-programmatically-in-ios

    boyvanamstel earned $50.00 by resolving this issue!

    enhancement help wanted :gift: Rewarded on Issuehunt 
    opened by sindresorhus 4
  • Expose a `lineWidth` property

    Expose a `lineWidth` property

    Issuehunt badges

    I tried changing 'lineWidthandradius` but it's not working. Please make it configurable. Snip20190704_6


    IssueHunt Summary

    serhii-londar serhii-londar has been rewarded.

    Backers (Total: $50.00)

    Submitted pull Requests


    Tips


    IssueHunt has been backed by the following sponsors. Become a sponsor

    enhancement help wanted :gift: Rewarded on Issuehunt 
    opened by preetam-jadakar 3
  • Improve mouse tracking

    Improve mouse tracking

    Issuehunt badges

    We currently do mouse tracking as a square around the circle, but that leads to the cancel state being activated even when the mouse is not over the circle. We should only activate the cancel state when the mouse is actually over the circle.

    https://stackoverflow.com/questions/38963011/nstrackingarea-for-custom-shapes


    IssueHunt Summary

    eonist eonist has been rewarded.

    Backers (Total: $60.00)

    Submitted pull Requests


    Tips


    IssueHunt has been backed by the following sponsors. Become a sponsor

    bug help wanted :gift: Rewarded on Issuehunt 
    opened by sindresorhus 3
  • Fix resetting color and variable scope

    Fix resetting color and variable scope

    Fixes #14 Fixes #15

    I tried a few things to reset the color after cancelling the progress. This seems to be the least obtrusive and avoids adding variables like originalColor etc. I think it fits the temporary nature of the color change.

    opened by boyvanamstel 3
  • Ensure `.isHidden` is set on the main thread

    Ensure `.isHidden` is set on the main thread

    I noticed the progress could be updated from a background thread. Toggling isHidden without switching to the main thread will throw warnings in the console.

    opened by boyvanamstel 3
  • Make a nicer success view

    Make a nicer success view

    Issuehunt badges

    Would be nice if it matched the thin style used for the cancel button in #4. So instead of just using a checkmark character, we could build it using paths.

    And some kind of animation. I like organic animations like https://twitter.com/twostraws/status/1088368799928193024

    IssueHunt Summary

    allewun allewun has been rewarded.

    Sponsors (Total: $142.00)

    Tips

    enhancement help wanted :gift: Rewarded on Issuehunt 
    opened by sindresorhus 3
  • Accept an `AsyncSequence`

    Accept an `AsyncSequence`

    Just like we do with Progress.

    When macOS 12 is out.

    https://github.com/apple/swift-evolution/blob/main/proposals/0314-async-stream.md

    I'm not yet sure what to call the API. I think we can just wait and see what kind of naming Apple decides to use for properties.

    opened by sindresorhus 0
  • SwiftUI and Combine support

    SwiftUI and Combine support

    https://developer.apple.com/tutorials/swiftui/ https://developer.apple.com/documentation/combine

    • [ ] Accept a AsyncSequence<Double, Never> to update the progress. (Does this make sense?)
    • [ ] Make it Swift View compatible by conforming to NSViewRepresentable
    • [ ] Expose SwiftUI bindings for the various states and ability to control states using bindings.
    • [ ] Add another example app that uses the SwiftUI interface and bindings.
    • [ ] Docs
    • [ ] Tests

    Anything other ideas?


    *This issue requires you to have advanced Swift knowledge.

    enhancement help wanted 
    opened by sindresorhus 0
  • Set up automatic docs generation

    Set up automatic docs generation

    I don't want to maintain a manual copy of the docs forever, but there are certain things I need before it's worth automating it:

    • [ ] GitHub Actions, so that I can automatically generate docs when a new Git tag is created. Yes, I could use Travis now, but I don't want to.
    • [ ] Jazzy / Swift support for showing default arguments. I think this will be supported in Swift 5, and Jazzy could then take advantage of it.
    opened by sindresorhus 0
Releases(v3.0.1)
  • v3.0.1(Dec 1, 2022)

  • v3.0.0(May 30, 2022)

    Breaking

    • Require macOS 10.15 and later
    • Drop support for CocoaPods and Carthage
    • The views are now annotated with @MainActor
    • .lineWidth is now a Double instead of CGFloat

    https://github.com/sindresorhus/CircularProgress/compare/v2.2.0...v3.0.0

    Source code(tar.gz)
    Source code(zip)
  • v2.2.0(Mar 19, 2021)

    • Add ability to hide label (#32) https://github.com/sindresorhus/CircularProgress/commit/bd6ae4afe56ac510a6b9656115a916f102c585e0

    https://github.com/sindresorhus/CircularProgress/compare/v2.1.0...v2.2.0

    Source code(tar.gz)
    Source code(zip)
  • v2.1.0(Nov 12, 2020)

    • Support KVO for .isFinished and .isCancelled https://github.com/sindresorhus/CircularProgress/commit/a292ebb4cf25fe6b15f62fba1b177cc990bf2a79

    https://github.com/sindresorhus/CircularProgress/compare/v2.0.2...v2.1.0

    Source code(tar.gz)
    Source code(zip)
  • v2.0.2(Jul 25, 2020)

  • v2.0.1(Feb 9, 2020)

  • v2.0.0(Dec 2, 2019)

    Breaking

    • Only allow calling the methods/properties from the main thread https://github.com/sindresorhus/CircularProgress/commit/cb46c8fce959cd81c7f6fb69544ed68bc5387737
    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Sep 17, 2019)

    • Upgrade to Swift 5.1 https://github.com/sindresorhus/CircularProgress/commit/e96dcc7c4c0dce222ead87ea5d105fe5d44ecf42
    • Add ability to change the line width https://github.com/sindresorhus/CircularProgress/commit/b1b1f299cdd2683bfe98439921f679eeee2f815e
    Source code(tar.gz)
    Source code(zip)
  • v0.4.1(Jun 23, 2019)

    • Don't show the success checkmark when cancelled https://github.com/sindresorhus/CircularProgress/commit/c79203e05ded221637379eb58e8ce5ba658a19bc
    Source code(tar.gz)
    Source code(zip)
  • v0.4.0(May 27, 2019)

    • Upgrade to Swift 5 https://github.com/sindresorhus/CircularProgress/commit/4b08258cbd749d65f95513de538aaafa45ea5a8c
    • Animate the success checkmark (#21) https://github.com/sindresorhus/CircularProgress/commit/7891df76691e533d030116915adf233451a0c4a5
    Source code(tar.gz)
    Source code(zip)
  • v0.3.0(Mar 5, 2019)

    • Add indeterminate state https://github.com/sindresorhus/CircularProgress/commit/e7c08ecab450b5a6e7ab147dc65a83513cacd2e9
    • Visualize cancelled state https://github.com/sindresorhus/CircularProgress/commit/2121abe0be5da9bfff05c6b04e0464617569ccea

    https://github.com/sindresorhus/CircularProgress/compare/v0.2.1...v0.3.0

    Source code(tar.gz)
    Source code(zip)
  • v0.2.1(Jan 31, 2019)

    • Fix obscure hover bug where if you pressed and held the cancel button, then moved the mouse outside the progress circle, it would get into an inconsistent state. https://github.com/sindresorhus/CircularProgress/commit/a1c468aa832a08ddb6e320015706475f81207670
    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(Jan 27, 2019)

    • Add ability to cancel the progress (#4) https://github.com/sindresorhus/CircularProgress/commit/711493ca8a52166fee4d12bba9a3adc5a5117cf0
    • Fix scaling in Interface Builder (#3) https://github.com/sindresorhus/CircularProgress/commit/f96eeb0421f5dd70e19fd9940adec4fac4697549
    Source code(tar.gz)
    Source code(zip)
  • v0.1.3(Jan 2, 2019)

Owner
Sindre Sorhus
Full-Time Open-Sourcerer. Wants more empathy & kindness in open source. Focuses on Swift & JavaScript. Makes macOS apps, CLI tools, npm packages. Likes unicorns
Sindre Sorhus
A custom reusable circular / progress slider control for iOS application.

HGCircularSlider Example To run the example project, clone the repo, and run pod install from the Example directory first. You also may like HGPlaceho

Hamza Ghazouani 2.4k Jan 6, 2023
Cool Animated music indicator view written in Swift

Cool Animated music indicator view written in Swift. ESTMusicIndicator is an implementation of NAKPlaybackIndicatorView in Swift for iOS 8. 本人著作的书籍《La

Aufree 465 Nov 28, 2022
An easy way to add a shimmering effect to any view with just one line of code. It is useful as an unobtrusive loading indicator.

LoadingShimmer An easy way to add a shimmering effect to any view with just single line of code. It is useful as an unobtrusive loading indicator. Thi

Jogendra 1.4k Jan 4, 2023
Show progress in your app's Dock icon

DockProgress Show progress in your app's Dock icon This package is used in production by the Gifski app. You might also like some of my other apps. Re

Sindre Sorhus 958 Jan 2, 2023
📊 A customizable gradient progress bar (UIProgressView).

GradientProgressBar A customizable gradient progress bar (UIProgressView). Inspired by iOS 7 Progress Bar from Codepen. Example To run the example pro

Felix M. 490 Dec 16, 2022
💈 Retro looking progress bar straight from the 90s

Description Do you miss the 90s? We know you do. Dial-up internet, flickering screens, brightly colored websites and, of course, this annoyingly slow

HyperRedink 18 Nov 24, 2022
Progress and Activity Indicators for iOS apps

Progress Indicators and Activity Views for iOS Apps Features Storyboard compatible, configure apprearance with the property inspector. fully animated,

Alexander Kasimir 101 Nov 13, 2022
Step-by-step progress view with labels and shapes. A good replacement for UIActivityIndicatorView and UIProgressView.

StepProgressView Step-by-step progress view with labels and shapes. A good replacement for UIActivityIndicatorView and UIProgressView. Usage let progr

Yonat Sharon 340 Dec 16, 2022
Work in progress gallery of controls available to Catalyst apps using Optimized for Mac

Catalyst Controls Gallery Very simple work-in-progress demonstration of many common controls available to Mac Catalyst as of macOS 11. Provided moreso

Steven Troughton-Smith 163 Sep 18, 2022
Measuring the progress with annotations 🔱

Description Displaying the progress in a meter control. ProgressMeter lets you create your custom annotations that display either on top or bottom of

Khawaja Farooq 108 Oct 5, 2022
A dynamically flowing progress bar.

WWProgressView A dynamically flowing progress bar. 一個動態流動的進度條. Installation with Swift Package Manager dependencies: [ .package(url: "https://gith

William-Weng 5 Jan 25, 2022
⚙ Add a preferences window to your macOS app in minutes

Preferences Add a preferences window to your macOS app in minutes Just pass in some view controllers and this package will take care of the rest. Requ

Sindre Sorhus 1.2k Jan 6, 2023
Twinkle is a Swift and easy way to make any UIView in your iOS or tvOS app twinkle.

Twinkle ✨ Twinkle is a Swift and easy way to make any UIView in your iOS or tvOS app twinkle. This library creates several CAEmitterLayers and animate

patrick piemonte 600 Nov 24, 2022
Confetti View lets you create a magnificent confetti view in your app

ConfettiView Confetti View lets you create a magnificent confetti view in your app. This was inspired by House Party app's login screen. Written in Sw

Or Ron 234 Nov 22, 2022
Super awesome Swift minion for Core Data (iOS, macOS, tvOS)

⚠️ Since this repository is going to be archived soon, I suggest migrating to NSPersistentContainer instead (available since iOS 10). For other conven

Marko Tadić 306 Sep 23, 2022
Programmatic UI for macOS

Description: Programmatic UI Framework for macOS. Swift handles app logic, CSS/SVG handles design and JSON handles struture. Installation: Step 1: Add

André J 860 Dec 18, 2022
UIPheonix is a super easy, flexible, dynamic and highly scalable UI framework + concept for building reusable component/control-driven apps for macOS, iOS and tvOS

UIPheonix is a super easy, flexible, dynamic and highly scalable UI framework + concept for building reusable component/control-driven apps for macOS, iOS and tvOS

Mohsan Khan 29 Sep 9, 2022
High performance Swift treemap layout engine for iOS and macOS.

Synopsis YMTreeMap is a high performance treemap layout engine for iOS and macOS, written in Swift. The input to YMTreeMap is a list of arbitrary numb

Yahoo 118 Jan 3, 2023
A window arrangement manager for macOS like BetterSnapTool and Magnet

A window arrangement manager for macOS like BetterSnapTool and Magnet. You can split the foremost window to the left half of the screen, the left two-thirds, etc.

Takuto NAKAMURA (Kyome) 65 Dec 9, 2022