This repository was archived by the owner on Mar 5, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathDetailViewController.swift
More file actions
120 lines (97 loc) · 3.82 KB
/
DetailViewController.swift
File metadata and controls
120 lines (97 loc) · 3.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import AppKit
import Combine
import SwiftUI
import OutlineViewDiffableDataSource
/// Tab view with editors for different types of selection.
final class DetailViewController: NSViewController {
/// An editor for the empty outline view selection.
private let emptyViewController: EmptyViewController
/// An editor for the single outline view item.
private let singleViewController: SingleViewController
/// An editor for multiple outline view items.
private let multiViewController: MultiViewController
/// Used to switch between different items.
private lazy var tabViewController: NSTabViewController = {
let viewController = NSTabViewController()
viewController.tabStyle = .unspecified
viewController.transitionOptions = []
viewController.tabViewItems = [emptyViewController, singleViewController, multiViewController]
.map(NSTabViewItem.init(viewController:))
return viewController
}()
/// The bottom checkbox which animates changes.
private lazy var animationCheckbox: (button: NSButton, unbind: AnyCancellable) = {
let checkbox = NSButton(checkboxWithTitle: "Animate Changes", target: nil, action: nil)
checkbox.bind(.value, to: NSUserDefaultsController.shared, withKeyPath: "values.ShouldAnimate", options: nil)
return (checkbox, .init { checkbox.unbind(.value) })
}()
/// Creates a new container for editing sidebar contents.
init(snapshotBinding: Binding<DiffableDataSourceSnapshot>) {
self.emptyViewController = .init(binding: snapshotBinding)
self.singleViewController = .init(binding: snapshotBinding)
self.multiViewController = .init(binding: snapshotBinding)
super.init(nibName: nil, bundle: nil)
}
@available(*, unavailable, message: "IB is denied")
required init?(coder: NSCoder) {
fatalError()
}
}
// MARK: -
extension DetailViewController {
/// This is a container for the tab view.
override func loadView() {
let separator = NSBox()
separator.translatesAutoresizingMaskIntoConstraints = false
separator.boxType = .separator
separator.heightAnchor.constraint(equalToConstant: 20).isActive = true
let stackView = NSStackView()
stackView.edgeInsets = .init(top: 20, left: 20, bottom: 20, right: 20)
stackView.orientation = .vertical
stackView.distribution = .fill
stackView.addView(tabViewController.view, in: .center)
stackView.addView(separator, in: .center)
stackView.addView(animationCheckbox.button, in: .center)
view = stackView
addChild(tabViewController)
}
/// Switches to the correct tab depending on the current selection.
override func viewDidLoad() {
super.viewDidLoad()
updateContents()
}
/// Switches to the correct tab depending on the current selection.
override var representedObject: Any? {
didSet {
updateContents()
}
}
}
// MARK: - Private API
private extension DetailViewController {
/// View controller represented by the selected tab.
var selectedViewController: NSViewController? {
get {
tabViewController.tabViewItems[tabViewController.selectedTabViewItemIndex].viewController
}
set {
let selectedIndex = tabViewController.tabViewItems.firstIndex { $0.viewController == newValue }
tabViewController.selectedTabViewItemIndex = selectedIndex ?? 0
}
}
/// Switches to the tab and assigns its represented object.
func updateContents() {
guard isViewLoaded else { return }
guard let selection = representedObject as? [MasterOutlineViewItem], selection.isEmpty == false else {
selectedViewController = emptyViewController
return
}
if selection.count == 1 {
singleViewController.representedObject = selection[0]
selectedViewController = singleViewController
} else {
multiViewController.representedObject = selection
selectedViewController = multiViewController
}
}
}