diff --git a/Packages/Sindresorhus_SSPreferences/Package.swift b/Packages/Sindresorhus_SSPreferences/Package.swift index f8e41f73..c761bf3d 100644 --- a/Packages/Sindresorhus_SSPreferences/Package.swift +++ b/Packages/Sindresorhus_SSPreferences/Package.swift @@ -1,10 +1,10 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.5 import PackageDescription let package = Package( name: "SSPreferences", platforms: [ - .macOS(.v10_11), + .macOS(.v10_13), ], products: [ .library( diff --git a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/SSPreferences.swift b/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/SSPreferences.swift deleted file mode 100755 index 4d8e8ade..00000000 --- a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/SSPreferences.swift +++ /dev/null @@ -1,6 +0,0 @@ -// (c) 2018 and onwards Sindre Sorhus (MIT License). -// ==================== -// This code is released under the MIT license (SPDX-License-Identifier: MIT) - -/// The namespace for this package. -public enum SSPreferences {} diff --git a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/Container.swift b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/Container.swift old mode 100755 new mode 100644 similarity index 58% rename from Packages/Sindresorhus_SSPreferences/Source/SSPreferences/Container.swift rename to Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/Container.swift index 7a3b9aa3..a0a8a2ed --- a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/Container.swift +++ b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/Container.swift @@ -5,9 +5,9 @@ import SwiftUI @available(macOS 10.15, *) -public extension SSPreferences { +public extension Settings { /** - Function builder for `Preferences` components used in order to restrict types of child views to be of type `Section`. + Function builder for `Settings` components used in order to restrict types of child views to be of type `Section`. */ @resultBuilder enum SectionBuilder { @@ -17,7 +17,7 @@ public extension SSPreferences { } /** - A view which holds `Preferences.Section` views and does all the alignment magic similar to `NSGridView` from AppKit. + A view which holds `Settings.Section` views and does all the alignment magic similar to `NSGridView` from AppKit. */ struct Container: View { private let sectionBuilder: () -> [Section] @@ -26,14 +26,14 @@ public extension SSPreferences { @State private var maximumLabelWidth = 0.0 /** - Creates an instance of container component, which handles layout of stacked `Preferences.Section` views. + Creates an instance of container component, which handles layout of stacked `Settings.Section` views. Custom alignment requires content width to be specified beforehand. - Parameters: - contentWidth: A fixed width of the container's content (excluding paddings). - minimumLabelWidth: A minimum width for labels within this container. By default, it will fit to the largest label. - - builder: A view builder that creates `Preferences.Section`'s of this container. + - builder: A view builder that creates `Settings.Section`'s of this container. */ public init( contentWidth: Double, @@ -47,21 +47,10 @@ public extension SSPreferences { public var body: some View { let sections = sectionBuilder() - let labelWidth = max(minimumLabelWidth, maximumLabelWidth) - return VStack(alignment: .preferenceSectionLabel) { + return VStack(alignment: .settingsSectionLabel) { ForEach(0 ..< sections.count, id: \.self) { index in - if sections[index].label != nil { - sections[index].bodyLimited(rightPaneWidth: contentWidth - labelWidth) - } else { - sections[index] - .alignmentGuide(.preferenceSectionLabel) { $0[.leading] + labelWidth } - } - if sections[index].bottomDivider, index < sections.count - 1 { - Divider() - .frame(height: 10) - .alignmentGuide(.preferenceSectionLabel) { $0[.leading] + labelWidth } - } + viewForSection(sections, index: index) } } .modifier(Section.LabelWidthModifier(maximumWidth: $maximumLabelWidth)) @@ -69,17 +58,31 @@ public extension SSPreferences { .padding(.vertical, 20) .padding(.horizontal, 30) } + + @ViewBuilder + private func viewForSection(_ sections: [Section], index: Int) -> some View { + sections[index] + if index != sections.count - 1, sections[index].bottomDivider { + Divider() + // Strangely doesn't work without width being specified. Probably because of custom alignment. + .frame(width: contentWidth, height: 20) + .alignmentGuide(.settingsSectionLabel) { $0[.leading] + max(minimumLabelWidth, maximumLabelWidth) } + } + } } } -/// Extension with custom alignment guide for section title labels. +/** + Extension with custom alignment guide for section title labels. + */ @available(macOS 10.15, *) extension HorizontalAlignment { - private enum PreferenceSectionLabelAlignment: AlignmentID { + private enum SettingsSectionLabelAlignment: AlignmentID { + // swiftlint:disable:next no_cgfloat static func defaultValue(in context: ViewDimensions) -> CGFloat { context[HorizontalAlignment.leading] } } - static let preferenceSectionLabel = HorizontalAlignment(PreferenceSectionLabelAlignment.self) + static let settingsSectionLabel = HorizontalAlignment(SettingsSectionLabelAlignment.self) } diff --git a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/Localization.swift b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/Localization.swift old mode 100755 new mode 100644 similarity index 63% rename from Packages/Sindresorhus_SSPreferences/Source/SSPreferences/Localization.swift rename to Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/Localization.swift index 62e68d20..7b71e790 --- a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/Localization.swift +++ b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/Localization.swift @@ -7,7 +7,7 @@ import Foundation struct Localization { enum Identifier { case preferences - case preferencesEllipsized + case settings } private static let localizedStrings: [Identifier: [String: String]] = [ @@ -52,46 +52,46 @@ struct Localization { "zh-HK": "偏好設定", "zh-TW": "偏好設定", ], - .preferencesEllipsized: [ - "ar": "تفضيلات…", - "ca": "Preferències…", - "cs": "Předvolby…", - "da": "Indstillinger…", - "de": "Einstellungen…", - "el": "Προτιμήσεις…", - "en": "Preferences…", - "en-AU": "Preferences…", - "en-GB": "Preferences…", - "es": "Preferencias…", - "es-419": "Preferencias…", - "fi": "Asetukset…", - "fr": "Préférences…", - "fr-CA": "Préférences…", - "he": "העדפות…", - "hi": "प्राथमिकता…", - "hr": "Postavke…", - "hu": "Beállítások…", - "id": "Preferensi…", - "it": "Preferenze…", - "ja": "環境設定…", - "ko": "환경설정...", - "ms": "Keutamaan…", - "nl": "Voorkeuren…", - "no": "Valg…", - "pl": "Preferencje…", - "pt": "Preferências…", - "pt-PT": "Preferências…", - "ro": "Preferințe…", - "ru": "Настройки…", - "sk": "Nastavenia…", - "sv": "Inställningar…", - "th": "การตั้งค่า…", - "tr": "Tercihler…", - "uk": "Параметри…", - "vi": "Tùy chọn…", - "zh-CN": "偏好设置…", - "zh-HK": "偏好設定⋯", - "zh-TW": "偏好設定⋯", + .settings: [ + "ar": "الإعدادات", + "ca": "Configuració", + "cs": "Nastavení", + "da": "Indstillinger", + "de": "Einstellungen", + "el": "Ρυθμίσεις", + "en": "Settings", + "en-AU": "Settings", + "en-GB": "Settings", + "es": "Ajustes", + "es-419": "Ajustes", + "fi": "Asetukset", + "fr": "Réglages", + "fr-CA": "Réglages", + "he": "הגדרות", + "hi": "समायोजन", + "hr": "Postavke", + "hu": "Beállítások", + "id": "Pengaturan", + "it": "Impostazioni", + "ja": "設定", + "ko": "설정", + "ms": "Tetapan", + "nl": "Instellingen", + "no": "Innstillinger", + "pl": "Ustawienia", + "pt": "Ajustes", + "pt-PT": "Definições", + "ro": "Configurări", + "ru": "Настройки", + "sk": "Nastavenia", + "sv": "Inställningar", + "th": "ค่าติดตั้ง", + "tr": "Ayarlar", + "uk": "Параметри", + "vi": "Cài đặt", + "zh-CN": "设置", + "zh-HK": "設定", + "zh-TW": "設定", ], ] @@ -104,16 +104,16 @@ struct Localization { */ static subscript(identifier: Identifier) -> String { // Force-unwrapped since all of the involved code is under our control. - let localizedDict = Self.localizedStrings[identifier]! + let localizedDict = Localization.localizedStrings[identifier]! let defaultLocalizedString = localizedDict["en"]! // Iterate through all user-preferred languages until we find one that has a valid language code. - let preferredLocale = - Locale.preferredLanguages - .lazy - .map { Locale(identifier: $0) } - .first { $0.languageCode != nil } - ?? .current + let preferredLocale = Locale.preferredLanguages + // TODO: Use `.firstNonNil()` here when available. + .lazy + .map { Locale(identifier: $0) } + .first { $0.languageCode != nil } + ?? .current guard let languageCode = preferredLocale.languageCode else { return defaultLocalizedString diff --git a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/Pane.swift b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/Pane.swift old mode 100755 new mode 100644 similarity index 70% rename from Packages/Sindresorhus_SSPreferences/Source/SSPreferences/Pane.swift rename to Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/Pane.swift index 434afb35..eb943ba1 --- a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/Pane.swift +++ b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/Pane.swift @@ -4,24 +4,26 @@ import SwiftUI -/// Represents a type that can be converted to `PreferencePane`. -/// -/// Acts as type-eraser for `Preferences.Pane`. -public protocol PreferencePaneConvertible { +/** + Represents a type that can be converted to `SettingsPane`. + + Acts as type-eraser for `Settings.Pane`. + */ +public protocol SettingsPaneConvertible { /** - Convert `self` to equivalent `PreferencePane`. + Convert `self` to equivalent `SettingsPane`. */ - func asPreferencePane() -> PreferencePane + func asPreferencePane() -> SettingsPane } @available(macOS 10.15, *) -public extension SSPreferences { +public extension Settings { /** - Create a SwiftUI-based preference pane. + Create a SwiftUI-based settings pane. - SwiftUI equivalent of the `PreferencePane` protocol. + SwiftUI equivalent of the `SettingsPane` protocol. */ - struct Pane: View, PreferencePaneConvertible { + struct Pane: View, SettingsPaneConvertible { let identifier: PaneIdentifier let title: String let toolbarIcon: NSImage @@ -41,15 +43,15 @@ public extension SSPreferences { public var body: some View { content } - public func asPreferencePane() -> PreferencePane { + public func asPreferencePane() -> SettingsPane { PaneHostingController(pane: self) } } /** - Hosting controller enabling `Preferences.Pane` to be used alongside AppKit `NSViewController`'s. + Hosting controller enabling `Settings.Pane` to be used alongside AppKit `NSViewController`'s. */ - final class PaneHostingController: NSHostingController, PreferencePane { + final class PaneHostingController: NSHostingController, SettingsPane { public let preferencePaneIdentifier: PaneIdentifier public let preferencePaneTitle: String public let toolbarItemIcon: NSImage @@ -86,12 +88,11 @@ public extension SSPreferences { @available(macOS 10.15, *) public extension View { /** - Applies font and color for a label used for describing a preference. + Applies font and color for a label used for describing a setting. */ func preferenceDescription() -> some View { font(.system(size: 11.0)) // TODO: Use `.foregroundStyle` when targeting macOS 12. .foregroundColor(.secondary) - .frame(maxWidth: .infinity, alignment: .leading) } } diff --git a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/Section.swift b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/Section.swift old mode 100755 new mode 100644 similarity index 53% rename from Packages/Sindresorhus_SSPreferences/Source/SSPreferences/Section.swift rename to Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/Section.swift index f236a61c..c71f2a97 --- a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/Section.swift +++ b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/Section.swift @@ -5,7 +5,7 @@ import SwiftUI @available(macOS 10.15, *) -public extension SSPreferences { +public extension Settings { /** Represents a section with right-aligned title and optional bottom divider. */ @@ -32,7 +32,10 @@ public extension SSPreferences { var body: some View { GeometryReader { geometry in Color.clear - .preference(key: LabelWidthPreferenceKey.self, value: Double(geometry.size.width)) + .preference( + key: LabelWidthPreferenceKey.self, + value: geometry.size.width + ) } } } @@ -46,53 +49,30 @@ public extension SSPreferences { func body(content: Content) -> some View { content .onPreferenceChange(LabelWidthPreferenceKey.self) { newMaximumWidth in - maximumWidth = Double(newMaximumWidth) + maximumWidth = newMaximumWidth } } } - public private(set) var label: AnyView? + public let label: AnyView public let content: AnyView public let bottomDivider: Bool public let verticalAlignment: VerticalAlignment /** - A section is responsible for controlling a single preference without Label. - - - Parameters: - - bottomDivider: Whether to place a `Divider` after the section content. Default is `false`. - - verticalAlignement: The vertical alignment of the section content. - - verticalAlignment: - - label: A view describing preference handled by this section. - - content: A content view. - */ - public init( - bottomDivider: Bool = false, - verticalAlignment: VerticalAlignment = .firstTextBaseline, - @ViewBuilder content: @escaping () -> Content - ) { - label = nil - self.bottomDivider = bottomDivider - self.verticalAlignment = verticalAlignment - let stack = VStack(alignment: .leading) { content() } - self.content = stack.eraseToAnyView() - } - - /** - A section is responsible for controlling a single preference. + A section is responsible for controlling a single setting. - Parameters: - bottomDivider: Whether to place a `Divider` after the section content. Default is `false`. - verticalAlignement: The vertical alignment of the section content. - - verticalAlignment: - - label: A view describing preference handled by this section. + - label: A view describing the setting handled by this section. - content: A content view. */ - public init( + public init( bottomDivider: Bool = false, verticalAlignment: VerticalAlignment = .firstTextBaseline, - label: @escaping () -> Label, - @ViewBuilder content: @escaping () -> Content + label: @escaping () -> some View, + @ViewBuilder content: @escaping () -> some View ) { self.label = label() .overlay(LabelOverlay()) @@ -104,57 +84,42 @@ public extension SSPreferences { } /** - Creates instance of section, responsible for controling single preference with `Text` as a `Label`. + Creates instance of section, responsible for controling a single setting with `Text` as a `Label`. - Parameters: - - title: A string describing preference handled by this section. + - title: A string describing the setting handled by this section. - bottomDivider: Whether to place a `Divider` after the section content. Default is `false`. - verticalAlignement: The vertical alignment of the section content. - - verticalAlignment: - content: A content view. */ - public init( - title: String? = nil, + public init( + title: String, bottomDivider: Bool = false, verticalAlignment: VerticalAlignment = .firstTextBaseline, - @ViewBuilder content: @escaping () -> Content + @ViewBuilder content: @escaping () -> some View ) { - if let title = title { - let textLabel = { - Text(title) - .font(.system(size: 13.0)) - .overlay(LabelOverlay()) - .eraseToAnyView() - } - self.init( - bottomDivider: bottomDivider, - verticalAlignment: verticalAlignment, - label: textLabel, - content: content - ) - return + let textLabel = { + Text(title) + .font(.system(size: 13.0)) + .overlay(LabelOverlay()) + .eraseToAnyView() } + self.init( bottomDivider: bottomDivider, verticalAlignment: verticalAlignment, + label: textLabel, content: content ) } - public func bodyLimited(rightPaneWidth: CGFloat? = nil) -> some View { - HStack(alignment: verticalAlignment) { - if let label = label { - label.alignmentGuide(.preferenceSectionLabel) { $0[.trailing] } - } - HStack { - content - Spacer() - }.frame(maxWidth: rightPaneWidth) - } - } - public var body: some View { - bodyLimited() + HStack(alignment: verticalAlignment) { + label + .alignmentGuide(.settingsSectionLabel) { $0[.trailing] } + content + Spacer() + } } } } diff --git a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/SegmentedControlStyleViewController.swift b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/SegmentedControlStyleViewController.swift old mode 100755 new mode 100644 similarity index 73% rename from Packages/Sindresorhus_SSPreferences/Source/SSPreferences/SegmentedControlStyleViewController.swift rename to Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/SegmentedControlStyleViewController.swift index dcdd3634..e47ac695 --- a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/SegmentedControlStyleViewController.swift +++ b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/SegmentedControlStyleViewController.swift @@ -12,7 +12,7 @@ extension NSUserInterfaceItemIdentifier { static let toolbarSegmentedControl = Self("toolbarSegmentedControl") } -final class SegmentedControlStyleViewController: NSViewController, PreferencesStyleController { +final class SegmentedControlStyleViewController: NSViewController, SettingsStyleController { var segmentedControl: NSSegmentedControl! { get { view as? NSSegmentedControl } set { @@ -22,13 +22,13 @@ final class SegmentedControlStyleViewController: NSViewController, PreferencesSt var isKeepingWindowCentered: Bool { true } - weak var delegate: PreferencesStyleControllerDelegate? + weak var delegate: SettingsStyleControllerDelegate? - private var preferencePanes: [PreferencePane]! + private var panes: [SettingsPane]! - required init(preferencePanes: [PreferencePane]) { + required init(panes: [SettingsPane]) { super.init(nibName: nil, bundle: nil) - self.preferencePanes = preferencePanes + self.panes = panes } @available(*, unavailable) @@ -37,12 +37,12 @@ final class SegmentedControlStyleViewController: NSViewController, PreferencesSt } override func loadView() { - view = createSegmentedControl(preferencePanes: preferencePanes) + view = createSegmentedControl(panes: panes) } - fileprivate func createSegmentedControl(preferencePanes: [PreferencePane]) -> NSSegmentedControl { + fileprivate func createSegmentedControl(panes: [SettingsPane]) -> NSSegmentedControl { let segmentedControl = NSSegmentedControl() - segmentedControl.segmentCount = preferencePanes.count + segmentedControl.segmentCount = panes.count segmentedControl.segmentStyle = .texturedSquare segmentedControl.target = self segmentedControl.action = #selector(segmentedControlAction) @@ -57,8 +57,8 @@ final class SegmentedControlStyleViewController: NSViewController, PreferencesSt let insets = CGSize(width: 36, height: 12) var maxSize = CGSize.zero - for preferencePane in preferencePanes { - let title = preferencePane.preferencePaneTitle + for pane in panes { + let title = pane.preferencePaneTitle let titleSize = title.size( withAttributes: [ .font: NSFont.systemFont(ofSize: NSFont.systemFontSize(for: .regular)), @@ -77,13 +77,13 @@ final class SegmentedControlStyleViewController: NSViewController, PreferencesSt ) }() - let segmentBorderWidth = Double(preferencePanes.count) + 1 - let segmentWidth = segmentSize.width * Double(preferencePanes.count) + segmentBorderWidth + let segmentBorderWidth = Double(panes.count) + 1 + let segmentWidth = segmentSize.width * Double(panes.count) + segmentBorderWidth let segmentHeight = segmentSize.height segmentedControl.frame = CGRect(x: 0, y: 0, width: segmentWidth, height: segmentHeight) - for (index, preferencePane) in preferencePanes.enumerated() { - segmentedControl.setLabel(preferencePane.preferencePaneTitle, forSegment: index) + for (index, pane) in panes.enumerated() { + segmentedControl.setLabel(pane.preferencePaneTitle, forSegment: index) segmentedControl.setWidth(segmentSize.width, forSegment: index) if let cell = segmentedControl.cell as? NSSegmentedCell { cell.setTag(index, forSegment: index) @@ -109,8 +109,8 @@ final class SegmentedControlStyleViewController: NSViewController, PreferencesSt ] } - func toolbarItem(preferenceIdentifier: SSPreferences.PaneIdentifier) -> NSToolbarItem? { - let toolbarItemIdentifier = preferenceIdentifier.toolbarItemIdentifier + func toolbarItem(paneIdentifier: Settings.PaneIdentifier) -> NSToolbarItem? { + let toolbarItemIdentifier = paneIdentifier.toolbarItemIdentifier precondition(toolbarItemIdentifier == .toolbarSegmentedControlItem) // When the segments outgrow the window, we need to provide a group of @@ -118,12 +118,12 @@ final class SegmentedControlStyleViewController: NSViewController, PreferencesSt // context menu that pops up at the right edge of the window. let toolbarItemGroup = NSToolbarItemGroup(itemIdentifier: toolbarItemIdentifier) toolbarItemGroup.view = segmentedControl - toolbarItemGroup.subitems = preferencePanes.enumerated().map { index, preferenceable -> NSToolbarItem in - let item = NSToolbarItem(itemIdentifier: .init("segment-\(preferenceable.preferencePaneTitle)")) - item.label = preferenceable.preferencePaneTitle + toolbarItemGroup.subitems = panes.enumerated().map { index, settingsPane in + let item = NSToolbarItem(itemIdentifier: .init("segment-\(settingsPane.preferencePaneTitle)")) + item.label = settingsPane.preferencePaneTitle let menuItem = NSMenuItem( - title: preferenceable.preferencePaneTitle, + title: settingsPane.preferencePaneTitle, action: #selector(segmentedControlMenuAction), keyEquivalent: "" ) diff --git a/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/Settings.swift b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/Settings.swift new file mode 100644 index 00000000..186a4948 --- /dev/null +++ b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/Settings.swift @@ -0,0 +1,15 @@ +// (c) 2018 and onwards Sindre Sorhus (MIT License). +// ==================== +// This code is released under the MIT license (SPDX-License-Identifier: MIT) + +/** + The namespace for this package. + */ +public enum Settings {} + +// TODO: Remove in the next major version. +// Preserve backwards compatibility. +public typealias Preferences = Settings +public typealias PreferencePane = SettingsPane +public typealias PreferencePaneConvertible = SettingsPaneConvertible +public typealias PreferencesWindowController = SettingsWindowController diff --git a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/PreferencePane.swift b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/SettingsPane.swift old mode 100755 new mode 100644 similarity index 79% rename from Packages/Sindresorhus_SSPreferences/Source/SSPreferences/PreferencePane.swift rename to Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/SettingsPane.swift index 292cd645..2ed5b2c5 --- a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/PreferencePane.swift +++ b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/SettingsPane.swift @@ -4,7 +4,7 @@ import Cocoa -public extension SSPreferences { +public extension Settings { struct PaneIdentifier: Hashable, RawRepresentable, Codable { public let rawValue: String @@ -14,13 +14,13 @@ public extension SSPreferences { } } -public protocol PreferencePane: NSViewController { - var preferencePaneIdentifier: SSPreferences.PaneIdentifier { get } +public protocol SettingsPane: NSViewController { + var preferencePaneIdentifier: Settings.PaneIdentifier { get } var preferencePaneTitle: String { get } var toolbarItemIcon: NSImage { get } } -public extension PreferencePane { +public extension SettingsPane { var toolbarItemIdentifier: NSToolbarItem.Identifier { preferencePaneIdentifier.toolbarItemIdentifier } @@ -28,7 +28,7 @@ public extension PreferencePane { var toolbarItemIcon: NSImage { .empty } } -public extension SSPreferences.PaneIdentifier { +public extension Settings.PaneIdentifier { init(_ rawValue: String) { self.init(rawValue: rawValue) } diff --git a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/PreferencesStyleController.swift b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/SettingsStyleController.swift old mode 100755 new mode 100644 similarity index 50% rename from Packages/Sindresorhus_SSPreferences/Source/SSPreferences/PreferencesStyleController.swift rename to Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/SettingsStyleController.swift index 31861cd0..59c25330 --- a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/PreferencesStyleController.swift +++ b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/SettingsStyleController.swift @@ -4,16 +4,16 @@ import Cocoa -protocol PreferencesStyleController: AnyObject { - var delegate: PreferencesStyleControllerDelegate? { get set } +protocol SettingsStyleController: AnyObject { + var delegate: SettingsStyleControllerDelegate? { get set } var isKeepingWindowCentered: Bool { get } func toolbarItemIdentifiers() -> [NSToolbarItem.Identifier] - func toolbarItem(preferenceIdentifier: SSPreferences.PaneIdentifier) -> NSToolbarItem? + func toolbarItem(paneIdentifier: Settings.PaneIdentifier) -> NSToolbarItem? func selectTab(index: Int) } -protocol PreferencesStyleControllerDelegate: AnyObject { - func activateTab(preferenceIdentifier: SSPreferences.PaneIdentifier, animated: Bool) +protocol SettingsStyleControllerDelegate: AnyObject { + func activateTab(paneIdentifier: Settings.PaneIdentifier, animated: Bool) func activateTab(index: Int, animated: Bool) } diff --git a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/PreferencesTabViewController.swift b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/SettingsTabViewController.swift old mode 100755 new mode 100644 similarity index 60% rename from Packages/Sindresorhus_SSPreferences/Source/SSPreferences/PreferencesTabViewController.swift rename to Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/SettingsTabViewController.swift index af44e008..6ae04db5 --- a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/PreferencesTabViewController.swift +++ b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/SettingsTabViewController.swift @@ -4,16 +4,16 @@ import Cocoa -final class PreferencesTabViewController: NSViewController, PreferencesStyleControllerDelegate { +final class SettingsTabViewController: NSViewController, SettingsStyleControllerDelegate { private var activeTab: Int? - private var preferencePanes = [PreferencePane]() - private var style: SSPreferences.Style? - internal var preferencePanesCount: Int { preferencePanes.count } - private var preferencesStyleController: PreferencesStyleController! - private var isKeepingWindowCentered: Bool { preferencesStyleController.isKeepingWindowCentered } + private var panes = [SettingsPane]() + private var style: Settings.Style? + internal var settingsPanesCount: Int { panes.count } + private var settingsStyleController: SettingsStyleController! + private var isKeepingWindowCentered: Bool { settingsStyleController.isKeepingWindowCentered } private var toolbarItemIdentifiers: [NSToolbarItem.Identifier] { - preferencesStyleController?.toolbarItemIdentifiers() ?? [] + settingsStyleController?.toolbarItemIdentifiers() ?? [] } var window: NSWindow! { view.window } @@ -21,11 +21,11 @@ final class PreferencesTabViewController: NSViewController, PreferencesStyleCont var isAnimated = true var activeViewController: NSViewController? { - guard let activeTab = activeTab else { + guard let activeTab else { return nil } - return preferencePanes[activeTab] + return panes[activeTab] } override func loadView() { @@ -33,12 +33,12 @@ final class PreferencesTabViewController: NSViewController, PreferencesStyleCont view.translatesAutoresizingMaskIntoConstraints = false } - func configure(preferencePanes: [PreferencePane], style: SSPreferences.Style) { - self.preferencePanes = preferencePanes + func configure(panes: [SettingsPane], style: Settings.Style) { + self.panes = panes self.style = style - children = preferencePanes + children = panes - let toolbar = NSToolbar(identifier: "PreferencesToolbar") + let toolbar = NSToolbar(identifier: "SettingsToolbar") toolbar.allowsUserCustomization = false toolbar.displayMode = .iconAndLabel toolbar.showsBaselineSeparator = true @@ -46,26 +46,22 @@ final class PreferencesTabViewController: NSViewController, PreferencesStyleCont switch style { case .segmentedControl: - preferencesStyleController = SegmentedControlStyleViewController(preferencePanes: preferencePanes) + settingsStyleController = SegmentedControlStyleViewController(panes: panes) case .toolbarItems: - preferencesStyleController = ToolbarItemStyleViewController( - preferencePanes: preferencePanes, + settingsStyleController = ToolbarItemStyleViewController( + panes: panes, toolbar: toolbar, centerToolbarItems: false ) } - preferencesStyleController.delegate = self + settingsStyleController.delegate = self - // Called last so that `preferencesStyleController` can be asked for items. + // Called last so that `settingsStyleController` can be asked for items. window.toolbar = toolbar } - func activateTab(preferencePane: PreferencePane, animated: Bool) { - activateTab(preferenceIdentifier: preferencePane.preferencePaneIdentifier, animated: animated) - } - - func activateTab(preferenceIdentifier: SSPreferences.PaneIdentifier, animated: Bool) { - guard let index = (preferencePanes.firstIndex { $0.preferencePaneIdentifier == preferenceIdentifier }) else { + func activateTab(paneIdentifier: Settings.PaneIdentifier, animated: Bool) { + guard let index = (panes.firstIndex { $0.preferencePaneIdentifier == paneIdentifier }) else { return activateTab(index: 0, animated: animated) } @@ -75,7 +71,7 @@ final class PreferencesTabViewController: NSViewController, PreferencesStyleCont func activateTab(index: Int, animated: Bool) { defer { activeTab = index - preferencesStyleController.selectTab(index: index) + settingsStyleController.selectTab(index: index) updateWindowTitle(tabIndex: index) } @@ -96,46 +92,50 @@ final class PreferencesTabViewController: NSViewController, PreferencesStyleCont } } - private func updateWindowTitle(tabIndex _: Int) { + private func updateWindowTitle(tabIndex: Int) { window.title = { - // if preferencePanes.count > 1 { - // return preferencePanes[tabIndex].preferencePaneTitle - // } else { - // let preferences = Localization[.preferences] - // let appName = Bundle.main.appName - // return "\(appName) \(preferences)" - // } - var preferencesTitleName = NSLocalizedString("vChewing Preferences…", comment: "") - preferencesTitleName.removeLast() - return preferencesTitleName + if panes.count > 1 { + return panes[tabIndex].preferencePaneTitle + } else { + let settings: String + if #available(macOS 13, *) { + settings = Localization[.settings] + } else { + settings = Localization[.preferences] + } + + let appName = Bundle.main.appName + return "\(appName) \(settings)" + } }() } - /// Cached constraints that pin `childViewController` views to the content view. + /** + Cached constraints that pin `childViewController` views to the content view. + */ private var activeChildViewConstraints = [NSLayoutConstraint]() private func immediatelyDisplayTab(index: Int) { - let toViewController = preferencePanes[index] + let toViewController = panes[index] view.addSubview(toViewController.view) activeChildViewConstraints = toViewController.view.constrainToSuperviewBounds() setWindowFrame(for: toViewController, animated: false) } private func animateTabTransition(index: Int, animated: Bool) { - guard let activeTab = activeTab else { - assertionFailure( - "animateTabTransition called before a tab was displayed; transition only works from one tab to another") + guard let activeTab else { + assertionFailure("animateTabTransition called before a tab was displayed; transition only works from one tab to another") immediatelyDisplayTab(index: index) return } - let fromViewController = preferencePanes[activeTab] - let toViewController = preferencePanes[index] + let fromViewController = panes[activeTab] + let toViewController = panes[index] // View controller animations only work on macOS 10.14 and newer. let options: NSViewController.TransitionOptions if #available(macOS 10.14, *) { - options = animated && isAnimated ? [.slideUp] : [] + options = animated && isAnimated ? [.crossfade] : [] } else { options = [] } @@ -157,18 +157,16 @@ final class PreferencesTabViewController: NSViewController, PreferencesStyleCont options: NSViewController.TransitionOptions = [], completionHandler completion: (() -> Void)? = nil ) { - let isAnimated = - options - .intersection([ - .crossfade, - .slideUp, - .slideDown, - .slideForward, - .slideBackward, - .slideLeft, - .slideRight, - ]) - .isEmpty == false + let isAnimated = options + .isDisjoint(with: [ + .crossfade, + .slideUp, + .slideDown, + .slideForward, + .slideBackward, + .slideLeft, + .slideRight, + ]) if isAnimated { NSAnimationContext.runAnimationGroup({ context in @@ -195,7 +193,7 @@ final class PreferencesTabViewController: NSViewController, PreferencesStyleCont } private func setWindowFrame(for viewController: NSViewController, animated: Bool = false) { - guard let window = window else { + guard let window else { preconditionFailure() } @@ -216,7 +214,7 @@ final class PreferencesTabViewController: NSViewController, PreferencesStyleCont } } -extension PreferencesTabViewController: NSToolbarDelegate { +extension SettingsTabViewController: NSToolbarDelegate { func toolbarDefaultItemIdentifiers(_: NSToolbar) -> [NSToolbarItem.Identifier] { toolbarItemIdentifiers } @@ -238,7 +236,6 @@ extension PreferencesTabViewController: NSToolbarDelegate { return nil } - return preferencesStyleController.toolbarItem( - preferenceIdentifier: SSPreferences.PaneIdentifier(fromToolbarItemIdentifier: itemIdentifier)) + return settingsStyleController.toolbarItem(paneIdentifier: .init(fromToolbarItemIdentifier: itemIdentifier)) } } diff --git a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/PreferencesWindowController.swift b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/SettingsWindowController.swift old mode 100755 new mode 100644 similarity index 60% rename from Packages/Sindresorhus_SSPreferences/Source/SSPreferences/PreferencesWindowController.swift rename to Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/SettingsWindowController.swift index 55dc64d5..3b4ca7f7 --- a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/PreferencesWindowController.swift +++ b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/SettingsWindowController.swift @@ -5,11 +5,11 @@ import Cocoa extension NSWindow.FrameAutosaveName { - static let preferences: NSWindow.FrameAutosaveName = "com.sindresorhus.Preferences.FrameAutosaveName" + static let settings: NSWindow.FrameAutosaveName = "com.sindresorhus.Preferences.FrameAutosaveName" } -public final class PreferencesWindowController: NSWindowController { - private let tabViewController = PreferencesTabViewController() +public final class SettingsWindowController: NSWindowController { + private let tabViewController = SettingsTabViewController() public var isAnimated: Bool { get { tabViewController.isAnimated } @@ -25,14 +25,13 @@ public final class PreferencesWindowController: NSWindowController { } private func updateToolbarVisibility() { - window?.toolbar?.isVisible = - (hidesToolbarForSingleItem == false) - || (tabViewController.preferencePanesCount > 1) + window?.toolbar?.isVisible = (hidesToolbarForSingleItem == false) + || (tabViewController.settingsPanesCount > 1) } public init( - preferencePanes: [PreferencePane], - style: SSPreferences.Style = .toolbarItems, + preferencePanes: [SettingsPane], + style: Settings.Style = .toolbarItems, animated: Bool = true, hidesToolbarForSingleItem: Bool = true ) { @@ -66,7 +65,7 @@ public final class PreferencesWindowController: NSWindowController { } tabViewController.isAnimated = animated - tabViewController.configure(preferencePanes: preferencePanes, style: style) + tabViewController.configure(panes: preferencePanes, style: style) updateToolbarVisibility() } @@ -81,20 +80,20 @@ public final class PreferencesWindowController: NSWindowController { } /** - Show the preferences window and brings it to front. + Show the settings window and brings it to front. - If you pass a `SSPreferences.PaneIdentifier`, the window will activate the corresponding tab. + If you pass a `Settings.PaneIdentifier`, the window will activate the corresponding tab. - - Parameter preferencePane: Identifier of the preference pane to display, or `nil` to show the tab that was open when the user last closed the window. + - Parameter preferencePane: Identifier of the settings pane to display, or `nil` to show the tab that was open when the user last closed the window. - Note: Unless you need to open a specific pane, prefer not to pass a parameter at all or `nil`. - See `close()` to close the window again. - See `showWindow(_:)` to show the window without the convenience of activating the app. */ - public func show(preferencePane preferenceIdentifier: SSPreferences.PaneIdentifier? = nil) { - if let preferenceIdentifier = preferenceIdentifier { - tabViewController.activateTab(preferenceIdentifier: preferenceIdentifier, animated: false) + public func show(preferencePane paneIdentifier: Settings.PaneIdentifier? = nil) { + if let paneIdentifier { + tabViewController.activateTab(paneIdentifier: paneIdentifier, animated: false) } else { tabViewController.restoreInitialTab() } @@ -106,24 +105,25 @@ public final class PreferencesWindowController: NSWindowController { private func restoreWindowPosition() { guard - let window = window, + let window, let screenContainingWindow = window.screen else { return } - window.setFrameOrigin( - CGPoint( - x: screenContainingWindow.visibleFrame.midX - window.frame.width / 2, - y: screenContainingWindow.visibleFrame.midY - window.frame.height / 2 - )) - window.setFrameUsingName(.preferences) - window.setFrameAutosaveName(.preferences) + window.setFrameOrigin(CGPoint( + x: screenContainingWindow.visibleFrame.midX - window.frame.width / 2, + y: screenContainingWindow.visibleFrame.midY - window.frame.height / 2 + )) + window.setFrameUsingName(.settings) + window.setFrameAutosaveName(.settings) } } -public extension PreferencesWindowController { - /// Returns the active pane if it responds to the given action. +public extension SettingsWindowController { + /** + Returns the active pane if it responds to the given action. + */ override func supplementalTarget(forAction action: Selector, sender: Any?) -> Any? { if let target = super.supplementalTarget(forAction: action, sender: sender) { return target @@ -133,15 +133,11 @@ public extension PreferencesWindowController { return nil } - if let target = NSApp.target(forAction: action, to: activeViewController, from: sender) as? NSResponder, - target.responds(to: action) - { + if let target = NSApp.target(forAction: action, to: activeViewController, from: sender) as? NSResponder, target.responds(to: action) { return target } - if let target = activeViewController.supplementalTarget(forAction: action, sender: sender) as? NSResponder, - target.responds(to: action) - { + if let target = activeViewController.supplementalTarget(forAction: action, sender: sender) as? NSResponder, target.responds(to: action) { return target } @@ -150,20 +146,18 @@ public extension PreferencesWindowController { } @available(macOS 10.15, *) -public extension PreferencesWindowController { +public extension SettingsWindowController { /** - Create a preferences window from only SwiftUI-based preference panes. + Create a settings window from only SwiftUI-based settings panes. */ convenience init( - panes: [PreferencePaneConvertible], - style: SSPreferences.Style = .toolbarItems, + panes: [SettingsPaneConvertible], + style: Settings.Style = .toolbarItems, animated: Bool = true, hidesToolbarForSingleItem: Bool = true ) { - let preferencePanes = panes.map { $0.asPreferencePane() } - self.init( - preferencePanes: preferencePanes, + preferencePanes: panes.map { $0.asPreferencePane() }, style: style, animated: animated, hidesToolbarForSingleItem: hidesToolbarForSingleItem diff --git a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/PreferencesStyle.swift b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/Style.swift old mode 100755 new mode 100644 similarity index 87% rename from Packages/Sindresorhus_SSPreferences/Source/SSPreferences/PreferencesStyle.swift rename to Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/Style.swift index cc506f4f..fdc7543c --- a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/PreferencesStyle.swift +++ b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/Style.swift @@ -4,7 +4,7 @@ import Cocoa -public extension SSPreferences { +public extension Settings { enum Style { case toolbarItems case segmentedControl diff --git a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/ToolbarItemStyleViewController.swift b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/ToolbarItemStyleViewController.swift old mode 100755 new mode 100644 similarity index 50% rename from Packages/Sindresorhus_SSPreferences/Source/SSPreferences/ToolbarItemStyleViewController.swift rename to Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/ToolbarItemStyleViewController.swift index 00b991bc..4ec74767 --- a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/ToolbarItemStyleViewController.swift +++ b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/ToolbarItemStyleViewController.swift @@ -4,15 +4,15 @@ import Cocoa -final class ToolbarItemStyleViewController: NSObject, PreferencesStyleController { +final class ToolbarItemStyleViewController: NSObject, SettingsStyleController { let toolbar: NSToolbar let centerToolbarItems: Bool - let preferencePanes: [PreferencePane] + let panes: [SettingsPane] var isKeepingWindowCentered: Bool { centerToolbarItems } - weak var delegate: PreferencesStyleControllerDelegate? + weak var delegate: SettingsStyleControllerDelegate? - init(preferencePanes: [PreferencePane], toolbar: NSToolbar, centerToolbarItems: Bool) { - self.preferencePanes = preferencePanes + init(panes: [SettingsPane], toolbar: NSToolbar, centerToolbarItems: Bool) { + self.panes = panes self.toolbar = toolbar self.centerToolbarItems = centerToolbarItems } @@ -24,8 +24,8 @@ final class ToolbarItemStyleViewController: NSObject, PreferencesStyleController toolbarItemIdentifiers.append(.flexibleSpace) } - for preferencePane in preferencePanes { - toolbarItemIdentifiers.append(preferencePane.toolbarItemIdentifier) + for pane in panes { + toolbarItemIdentifiers.append(pane.toolbarItemIdentifier) } if centerToolbarItems { @@ -35,14 +35,14 @@ final class ToolbarItemStyleViewController: NSObject, PreferencesStyleController return toolbarItemIdentifiers } - func toolbarItem(preferenceIdentifier: SSPreferences.PaneIdentifier) -> NSToolbarItem? { - guard let preference = (preferencePanes.first { $0.preferencePaneIdentifier == preferenceIdentifier }) else { + func toolbarItem(paneIdentifier: Settings.PaneIdentifier) -> NSToolbarItem? { + guard let pane = (panes.first { $0.preferencePaneIdentifier == paneIdentifier }) else { preconditionFailure() } - let toolbarItem = NSToolbarItem(itemIdentifier: preferenceIdentifier.toolbarItemIdentifier) - toolbarItem.label = preference.preferencePaneTitle - toolbarItem.image = preference.toolbarItemIcon + let toolbarItem = NSToolbarItem(itemIdentifier: paneIdentifier.toolbarItemIdentifier) + toolbarItem.label = pane.preferencePaneTitle + toolbarItem.image = pane.toolbarItemIcon toolbarItem.target = self toolbarItem.action = #selector(toolbarItemSelected) return toolbarItem @@ -50,12 +50,12 @@ final class ToolbarItemStyleViewController: NSObject, PreferencesStyleController @IBAction private func toolbarItemSelected(_ toolbarItem: NSToolbarItem) { delegate?.activateTab( - preferenceIdentifier: SSPreferences.PaneIdentifier(fromToolbarItemIdentifier: toolbarItem.itemIdentifier), + paneIdentifier: .init(fromToolbarItemIdentifier: toolbarItem.itemIdentifier), animated: true ) } func selectTab(index: Int) { - toolbar.selectedItemIdentifier = preferencePanes[index].toolbarItemIdentifier + toolbar.selectedItemIdentifier = panes[index].toolbarItemIdentifier } } diff --git a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/Utilities.swift b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/Utilities.swift old mode 100755 new mode 100644 similarity index 52% rename from Packages/Sindresorhus_SSPreferences/Source/SSPreferences/Utilities.swift rename to Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/Utilities.swift index f0d58bb6..1b1f2918 --- a/Packages/Sindresorhus_SSPreferences/Source/SSPreferences/Utilities.swift +++ b/Packages/Sindresorhus_SSPreferences/Sources/SSPreferences/Utilities.swift @@ -2,7 +2,6 @@ // ==================== // This code is released under the MIT license (SPDX-License-Identifier: MIT) -import Cocoa import SwiftUI extension NSImage { @@ -12,21 +11,13 @@ extension NSImage { extension NSView { @discardableResult func constrainToSuperviewBounds() -> [NSLayoutConstraint] { - guard let superview = superview else { + guard let superview else { preconditionFailure("superview has to be set first") } var result = [NSLayoutConstraint]() - result.append( - contentsOf: NSLayoutConstraint.constraints( - withVisualFormat: "H:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, - views: ["subview": self] - )) - result.append( - contentsOf: NSLayoutConstraint.constraints( - withVisualFormat: "V:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, - views: ["subview": self] - )) + result.append(contentsOf: NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self])) + result.append(contentsOf: NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self])) translatesAutoresizingMaskIntoConstraints = false superview.addConstraints(result) @@ -35,42 +26,39 @@ extension NSView { } extension NSEvent { - /// Events triggered by user interaction. - static let userInteractionEvents: [NSEvent.EventType] = { - var events: [NSEvent.EventType] = [ - .leftMouseDown, - .leftMouseUp, - .rightMouseDown, - .rightMouseUp, - .leftMouseDragged, - .rightMouseDragged, - .keyDown, - .keyUp, - .scrollWheel, - .tabletPoint, - .otherMouseDown, - .otherMouseUp, - .otherMouseDragged, - .gesture, - .magnify, - .swipe, - .rotate, - .beginGesture, - .endGesture, - .smartMagnify, - .quickLook, - .directTouch, - ] + /** + Events triggered by user interaction. + */ + static let userInteractionEvents: [EventType] = [ + .leftMouseDown, + .leftMouseUp, + .rightMouseDown, + .rightMouseUp, + .leftMouseDragged, + .rightMouseDragged, + .keyDown, + .keyUp, + .scrollWheel, + .tabletPoint, + .otherMouseDown, + .otherMouseUp, + .otherMouseDragged, + .gesture, + .magnify, + .swipe, + .rotate, + .beginGesture, + .endGesture, + .smartMagnify, + .pressure, + .quickLook, + .directTouch, + ] - if #available(macOS 10.10.3, *) { - events.append(.pressure) - } - - return events - }() - - /// Whether the event was triggered by user interaction. - var isUserInteraction: Bool { NSEvent.userInteractionEvents.contains(type) } + /** + Whether the event was triggered by user interaction. + */ + var isUserInteraction: Bool { Self.userInteractionEvents.contains(type) } } extension Bundle { @@ -87,10 +75,12 @@ extension Bundle { } } -/// A window that allows you to disable all user interactions via `isUserInteractionEnabled`. -/// -/// Used to avoid breaking animations when the user clicks too fast. Disable user interactions during animations and you're set. -class UserInteractionPausableWindow: NSWindow { +/** + A window that allows you to disable all user interactions via `isUserInteractionEnabled`. + + Used to avoid breaking animations when the user clicks too fast. Disable user interactions during animations and you're set. + */ +class UserInteractionPausableWindow: NSWindow { // swiftlint:disable:this final_class var isUserInteractionEnabled = true override func sendEvent(_ event: NSEvent) {