Skip to content

Commit

Permalink
Add documentation and make classes final
Browse files Browse the repository at this point in the history
- Add documentation to functions
- Move ViewKit `typealias` to a separate file
- Add `final` to classes used throughout the source code
  • Loading branch information
zenangst committed Oct 24, 2020
1 parent 68c1602 commit e64beee
Show file tree
Hide file tree
Showing 43 changed files with 178 additions and 70 deletions.
4 changes: 4 additions & 0 deletions App/Sources/Application/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate,
fileName: configuration.fileName)
}

// MARK: Application life cycle

func applicationDidFinishLaunching(_ notification: Notification) {
if launchArguments.isEnabled(.runningUnitTests) { return }
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] != nil { return }
Expand All @@ -50,6 +52,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate,
shouldOpenMainWindow = true
}

// MARK: Private methods

private func createAndOpenWindow(_ coreController: CoreControlling) {
let window = createMainWindow(coreController)
window?.makeKeyAndOrderFront(NSApp)
Expand Down
4 changes: 3 additions & 1 deletion App/Sources/Application/AppDelegateErrorController.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import Cocoa

class AppDelegateErrorController {
final class AppDelegateErrorController {
/// Display an error using `NSAlert`
/// - Parameter error: The error that should be displayed
static func handle(_ error: Error) {
let alert = NSAlert()
alert.messageText = error.localizedDescription
Expand Down
10 changes: 9 additions & 1 deletion App/Sources/Application/AppDelegateLaunchController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,21 @@ import Cocoa
import LaunchArguments
import LogicFramework

class AppDelegateLaunchController {
final class AppDelegateLaunchController {
let factory: ControllerFactory

init(factory: ControllerFactory) {
self.factory = factory
}

/// Construct the applications `CoreController` and configure it using
/// launch arguments.
///
/// - Parameter storageController: The storage controller that is used to load
/// information from disk.
/// - Throws: If the storage cannot be loaded properly, this method will throw
/// a `StorageControllingError`
/// - Returns: A controller that conforms to `CoreControlling`
func initialLoad(storageController: StorageControlling) throws -> CoreControlling {
let groups = try storageController.load()
let groupsController = factory.groupsController(groups: groups)
Expand Down
9 changes: 9 additions & 0 deletions App/Sources/Application/LaunchArgument.swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import LaunchArguments

enum LaunchArgument: String, LaunchArgumentType {
// Used to avoid running the application when running unit tests
case runningUnitTests = "-running-unit-tests"
// Determines if the main window should open at launch.
// Encourage during development to ease the development process
// while testing changes.
case openWindowAtLaunch = "-open-window-at-launch"
// Disable setting up keyboard shortcut during development.
case disableKeyboardShortcuts = "-disable-keyboard-shortcuts"
// When enabled, the application will use the bundled JSON file
// to display information.
case demoMode = "-demo-mode"
// Will print information to the console while running the
// application. Great for debugging.
case debug = "-debug"
}
10 changes: 5 additions & 5 deletions App/Sources/Commands/CommandsFeatureController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ protocol CommandsFeatureControllerDelegate: AnyObject {
didDeleteCommand command: Command, in workflow: Workflow)
}

class CommandsFeatureController: ViewController {
final class CommandsFeatureController: ViewController {
weak var delegate: CommandsFeatureControllerDelegate?
@Published var state: [Command]
let userSelection: UserSelection
Expand Down Expand Up @@ -57,25 +57,25 @@ class CommandsFeatureController: ViewController {

// MARK: Private methods

func createCommand(_ command: Command, in workflow: Workflow) {
private func createCommand(_ command: Command, in workflow: Workflow) {
var workflow = workflow
workflow.commands.append(command)
delegate?.commandsFeatureController(self, didCreateCommand: command, in: workflow)
}

func updateCommand(_ command: Command, in workflow: Workflow) {
private func updateCommand(_ command: Command, in workflow: Workflow) {
var workflow = workflow
try? workflow.commands.replace(command)
delegate?.commandsFeatureController(self, didCreateCommand: command, in: workflow)
}

func moveCommand(_ command: Command, to index: Int, in workflow: Workflow) {
private func moveCommand(_ command: Command, to index: Int, in workflow: Workflow) {
var workflow = workflow
try? workflow.commands.move(command, to: index)
delegate?.commandsFeatureController(self, didUpdateCommand: command, in: workflow)
}

func deleteCommand(_ command: Command, in workflow: Workflow) {
private func deleteCommand(_ command: Command, in workflow: Workflow) {
var workflow = workflow
try? workflow.commands.remove(command)
delegate?.commandsFeatureController(self, didDeleteCommand: command, in: workflow)
Expand Down
5 changes: 5 additions & 0 deletions App/Sources/Configuration/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@ import Foundation

struct Configuration {
struct Storage {
/// The path to the configuration file
var path: String {
launchArguments.isEnabled(.demoMode)
? ProcessInfo.processInfo.environment["SOURCE_ROOT"]!
: UserDefaults.standard.string(forKey: "configurationPath") ?? "~"
}
/// Determines if the file name should use `.` as a prefix in order
/// to hide it in the Finder
var hiddenFile: Bool = true
/// A computed variable that changes depending on `hiddenFile`.
/// The file name is either `.keyboard-cowboy.json` or `keyboard-cowboy.json`
var fileName: String {
(hiddenFile && !launchArguments.isEnabled(.demoMode))
? ".keyboard-cowboy.json"
Expand Down
2 changes: 1 addition & 1 deletion App/Sources/FilePicker/FilePickerViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import LogicFramework
import Combine
import Cocoa

class OpenPanelViewController: NSObject, ViewController, NSOpenSavePanelDelegate {
final class OpenPanelViewController: NSObject, ViewController, NSOpenSavePanelDelegate {

@Published var state: String = ""
var fileExtension: String?
Expand Down
19 changes: 10 additions & 9 deletions App/Sources/Groups/GroupsFeatureController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ protocol GroupsFeatureControllerDelegate: AnyObject {
func groupsFeatureController(_ controller: GroupsFeatureController, didReloadGroups groups: [Group])
}

class GroupsFeatureController: ViewController, WorkflowFeatureControllerDelegate {
final class GroupsFeatureController: ViewController, WorkflowFeatureControllerDelegate {
weak var delegate: GroupsFeatureControllerDelegate?

@Published var state = [Group]()
Expand Down Expand Up @@ -59,9 +59,9 @@ class GroupsFeatureController: ViewController, WorkflowFeatureControllerDelegate
let group = Group.empty()
var groups = groupsController.groups
groups.append(group)
reload(groups) { _ in
self.userSelection.group = group
self.userSelection.workflow = nil
reload(groups) { [weak self] _ in
self?.userSelection.group = group
self?.userSelection.workflow = nil
}
}

Expand All @@ -73,9 +73,9 @@ class GroupsFeatureController: ViewController, WorkflowFeatureControllerDelegate
var groups = groupsController.groups
let group = Group.droppedApplication(application)
groups.append(group)
reload(groups) { _ in
self.userSelection.group = group
self.userSelection.workflow = nil
reload(groups) { [weak self] _ in
self?.userSelection.group = group
self?.userSelection.workflow = nil
}
}

Expand All @@ -97,8 +97,9 @@ class GroupsFeatureController: ViewController, WorkflowFeatureControllerDelegate
private func save(_ group: ModelKit.Group) {
var groups = groupsController.groups
try? groups.replace(group)
reload(groups)
userSelection.group = group
reload(groups) { [weak self] _ in
self?.userSelection.group = group
}
}

private func delete(_ group: ModelKit.Group) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import LogicFramework
import Combine
import ModelKit

class ApplicationsProvider: StateController {
final class ApplicationsProvider: StateController {
@Published var state: [Application] = []

init(applications: [Application]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ protocol KeyboardShortcutsFeatureControllerDelegate: AnyObject {

}

class KeyboardShortcutsFeatureController: ViewController {
final class KeyboardShortcutsFeatureController: ViewController {
weak var delegate: KeyboardShortcutsFeatureControllerDelegate?

@Published var state: [KeyboardShortcut]
Expand Down
2 changes: 1 addition & 1 deletion App/Sources/Menus/AppMenu.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Cocoa

class AppMenu: NSMenu {
final class AppMenu: NSMenu {
override init(title: String) {
super.init(title: title)
items = [
Expand Down
2 changes: 1 addition & 1 deletion App/Sources/Menus/EditMenu.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Cocoa

class EditMenu: NSMenuItem {
final class EditMenu: NSMenuItem {
init() {
super.init(title: "", action: nil, keyEquivalent: "")
submenu = NSMenu(title: "Edit")
Expand Down
2 changes: 1 addition & 1 deletion App/Sources/Menus/FileMenu.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Cocoa

class FileMenu: NSMenuItem {
final class FileMenu: NSMenuItem {
init() {
super.init(title: "", action: nil, keyEquivalent: "")
submenu = NSMenu(title: "File")
Expand Down
2 changes: 1 addition & 1 deletion App/Sources/Menus/HelpMenu.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Cocoa

class HelpMenu: NSMenuItem {
final class HelpMenu: NSMenuItem {
init() {
super.init(title: "", action: nil, keyEquivalent: "")
submenu = NSMenu(title: "Help")
Expand Down
2 changes: 1 addition & 1 deletion App/Sources/Menus/MainMenu.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Cocoa

class MainMenu: NSMenuItem {
final class MainMenu: NSMenuItem {
private lazy var applicationName = ProcessInfo.processInfo.processName

init() {
Expand Down
2 changes: 1 addition & 1 deletion App/Sources/Menus/WindowMenu.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Cocoa

class WindowMenu: NSMenuItem {
final class WindowMenu: NSMenuItem {
init() {
super.init(title: "", action: nil, keyEquivalent: "")
submenu = NSMenu(title: "Window")
Expand Down
6 changes: 5 additions & 1 deletion App/Sources/Permissions/PermissionsController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@ protocol PermissionsControlling {
func hasPrivileges() -> Bool
}

class PermissionsController: PermissionsControlling {
final class PermissionsController: PermissionsControlling {
/// Check if the application has the permissions to use accessiblity
/// - Returns: True if the application has been granted permissions.
func hasPrivileges() -> Bool {
let options: [String: Bool] = [
kAXTrustedCheckOptionPrompt.takeUnretainedValue() as String: true
]
return AXIsProcessTrustedWithOptions(options as CFDictionary)
}

/// Display modal message using `NSAlert` and ask the user to provide
/// accessibility permissions for the application
func displayModal() {
let applicationName = ProcessInfo.processInfo.processName
let alert = NSAlert()
Expand Down
2 changes: 1 addition & 1 deletion App/Sources/Search/SearchCommandsController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import ViewKit
import SwiftUI
import Combine

class SearchCommandsController: StateController {
final class SearchCommandsController: StateController {
@Published var state = ModelKit.SearchResult.commands([])
let searchWorkflowController: SearchWorkflowController
var query: String = ""
Expand Down
2 changes: 1 addition & 1 deletion App/Sources/Search/SearchFeatureController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import ViewKit
import SwiftUI
import Combine

class SearchFeatureController: ViewController {
final class SearchFeatureController: ViewController {
@Published var state = ModelKit.SearchResults.empty()
let searchController: SearchRootController
var userSelection: UserSelection
Expand Down
2 changes: 1 addition & 1 deletion App/Sources/Search/SearchGroupsController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ import Foundation
import ModelKit
import ViewKit

class SearchGroupsController: StateController {
final class SearchGroupsController: StateController {
@Published var state = ModelKit.SearchResult.groups([])
}
2 changes: 1 addition & 1 deletion App/Sources/Search/SearchRootController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import ViewKit
import SwiftUI
import Combine

class SearchRootController {
final class SearchRootController {
@Published var state: ModelKit.SearchResults = .empty()
let commandSearch: SearchCommandsController
let groupSearch: SearchGroupsController
Expand Down
2 changes: 1 addition & 1 deletion App/Sources/Search/SearchWorkflowController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import ViewKit
import SwiftUI
import Combine

class SearchWorkflowController: StateController {
final class SearchWorkflowController: StateController {
@Published var state = ModelKit.SearchResult.workflows([])
let searchGroupController: SearchGroupsController
var anyCancellables = [AnyCancellable]()
Expand Down
2 changes: 1 addition & 1 deletion App/Sources/Workflow/WorkflowFeatureController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ protocol WorkflowFeatureControllerDelegate: AnyObject {
in group: Group)
}

class WorkflowFeatureController: ViewController,
final class WorkflowFeatureController: ViewController,
CommandsFeatureControllerDelegate,
KeyboardShortcutsFeatureControllerDelegate {
weak var delegate: WorkflowFeatureControllerDelegate?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public enum ApplicationCommandControllingError: Error {
case failedToActivate(ApplicationCommand)
}

class ApplicationCommandController: ApplicationCommandControlling {
final class ApplicationCommandController: ApplicationCommandControlling {
let windowListProvider: WindowListProviding
let workspace: WorkspaceProviding

Expand Down
18 changes: 17 additions & 1 deletion LogicFramework/Sources/Applications/ApplicationParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@ import Cocoa
import Foundation
import ModelKit

class ApplicationParser {
final class ApplicationParser {
/// Resolve an `Application` model from an application at a certain url.
///
/// Parsing is done by invoking `Bundle(url:)` and verifying the contents
/// of the applications property list.
///
/// - Parameter url: The url of the application
/// - Returns: A `Application` if all the validation critieras are met, otherwise
/// if will simply return `nil`
func process(_ url: URL) -> Application? {
guard let bundle = Bundle(url: url),
let bundleIdentifier = bundle.bundleIdentifier,
Expand All @@ -27,6 +35,14 @@ class ApplicationParser {
path: bundle.bundlePath)
}

/// Verify existence of certain keys, only one of the keys must match
/// the dictionary that is used as the subject for validation.
///
/// - Parameters:
/// - dictionary: The dictionary that should be validated
/// - keys: An array of keys that should be used for validation
/// - Returns: Only one of the keys must match the dictionary in order for the method
/// to return true
private func checkDictionary(dictionary: [String: Any], for keys: [String]) -> Bool {
let lhs = Set<String>(dictionary.keys)
let rhs = Set<String>(keys)
Expand Down
6 changes: 5 additions & 1 deletion LogicFramework/Sources/Applications/WindowListProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ public protocol WindowListProviding {
func windowOwners() -> [String]
}

class WindowListProvider: WindowListProviding {
final class WindowListProvider: WindowListProviding {
/// Get a list of owners based on the currently open windows.
///
/// - Returns: A collection of window names, the window names are the bundle
/// names of the window owner.
func windowOwners() -> [String] {
let info = CGWindowListCopyWindowInfo(.optionOnScreenOnly, kCGNullWindowID) as? [[String: Any]] ?? []
return info.filter {
Expand Down
2 changes: 1 addition & 1 deletion LogicFramework/Sources/Commands/CommandController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public enum CommandControllerError: Error {
case failedToRunCommand(Error)
}

public class CommandController: CommandControlling {
public final class CommandController: CommandControlling {
weak public var delegate: CommandControllingDelegate?

let applicationCommandController: ApplicationCommandControlling
Expand Down
2 changes: 1 addition & 1 deletion LogicFramework/Sources/Debug/Debug.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

public class Debug {
public final class Debug {
public static var isEnabled: Bool = false

public static func print(_ statement: String,
Expand Down
Loading

0 comments on commit e64beee

Please sign in to comment.