mirror of
https://github.com/morgan9e/macos-stats
synced 2026-04-15 00:34:08 +09:00
feat: redesigned the settings view to work with light/dark mode (#1008)
This commit is contained in:
@@ -21,8 +21,8 @@ public struct Popup_c_s {
|
||||
}
|
||||
|
||||
public struct Settings_c_s {
|
||||
public let width: CGFloat = 539
|
||||
public let height: CGFloat = 479
|
||||
public let width: CGFloat = 540
|
||||
public let height: CGFloat = 480
|
||||
public let margin: CGFloat = 10
|
||||
public let row: CGFloat = 30
|
||||
}
|
||||
|
||||
@@ -131,13 +131,6 @@ open class Module: Module_p {
|
||||
moduleSettings: self.settingsView,
|
||||
popupSettings: self.popupView
|
||||
)
|
||||
self.settings?.toggleCallback = { [weak self] in
|
||||
self?.toggleEnabled()
|
||||
if self?.pauseState == true {
|
||||
self?.pauseState = false
|
||||
NotificationCenter.default.post(name: .pause, object: nil, userInfo: ["state": false])
|
||||
}
|
||||
}
|
||||
|
||||
self.popup = PopupWindow(title: self.config.name, view: self.popupView, visibilityCallback: self.visibilityCallback)
|
||||
}
|
||||
@@ -208,15 +201,6 @@ open class Module: Module_p {
|
||||
debug("Module disabled", log: self.log)
|
||||
}
|
||||
|
||||
// toggle module state
|
||||
private func toggleEnabled() {
|
||||
if self.enabled {
|
||||
self.disable()
|
||||
} else {
|
||||
self.enable()
|
||||
}
|
||||
}
|
||||
|
||||
// add reader to module. If module is enabled will fire a read function and start a reader
|
||||
public func addReader(_ reader: Reader_p) {
|
||||
self.readers.append(reader)
|
||||
@@ -320,8 +304,19 @@ open class Module: Module_p {
|
||||
} else if !state && self.enabled {
|
||||
self.disable()
|
||||
}
|
||||
} else {
|
||||
if self.enabled {
|
||||
self.disable()
|
||||
} else {
|
||||
self.enable()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.pauseState == true {
|
||||
self.pauseState = false
|
||||
NotificationCenter.default.post(name: .pause, object: nil, userInfo: ["state": false])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
import Cocoa
|
||||
|
||||
public protocol Settings_p: NSView {
|
||||
var toggleCallback: () -> Void { get set }
|
||||
func setState(_ newState: Bool)
|
||||
}
|
||||
|
||||
@@ -22,8 +21,6 @@ public protocol Settings_v: NSView {
|
||||
}
|
||||
|
||||
open class Settings: NSStackView, Settings_p {
|
||||
public var toggleCallback: () -> Void = {}
|
||||
|
||||
private var config: UnsafePointer<module_c>
|
||||
private var widgets: [Widget]
|
||||
private var moduleSettings: Settings_v?
|
||||
@@ -35,14 +32,6 @@ open class Settings: NSStackView, Settings_p {
|
||||
|
||||
private var enableControl: NSControl?
|
||||
|
||||
private let headerSeparator: NSView = {
|
||||
let view: NSView = NSView()
|
||||
view.heightAnchor.constraint(equalToConstant: 1).isActive = true
|
||||
view.wantsLayer = true
|
||||
view.layer?.backgroundColor = NSColor(hexString: "#d1d1d1").cgColor
|
||||
|
||||
return view
|
||||
}()
|
||||
private let noWidgetsView: EmptyView = EmptyView(msg: localizedString("No available widgets to configure"))
|
||||
private let noPopupSettingsView: EmptyView = EmptyView(msg: localizedString("No options to configure for the popup in this module"))
|
||||
|
||||
@@ -61,136 +50,43 @@ open class Settings: NSStackView, Settings_p {
|
||||
self.moduleSettings = moduleSettings
|
||||
self.popupSettings = popupSettings
|
||||
|
||||
super.init(frame: NSRect(x: 0, y: 0, width: Constants.Settings.width, height: Constants.Settings.height))
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(externalModuleToggle), name: .toggleModule, object: nil)
|
||||
|
||||
self.wantsLayer = true
|
||||
self.appearance = NSAppearance(named: .aqua)
|
||||
self.layer?.backgroundColor = NSColor(hexString: "#ececec").cgColor
|
||||
super.init(frame: NSRect.zero)
|
||||
|
||||
self.orientation = .vertical
|
||||
self.alignment = .width
|
||||
self.distribution = .fill
|
||||
self.spacing = 0
|
||||
|
||||
self.addArrangedSubview(self.header(enabled))
|
||||
self.addArrangedSubview(self.headerSeparator)
|
||||
self.addArrangedSubview(self.body())
|
||||
|
||||
self.addArrangedSubview(NSView())
|
||||
}
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
required public init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
// MARK: - parts
|
||||
|
||||
private func header(_ enabled: Bool) -> NSStackView {
|
||||
let view: NSStackView = NSStackView()
|
||||
|
||||
view.orientation = .horizontal
|
||||
view.distribution = .fillEqually
|
||||
view.alignment = .centerY
|
||||
view.distribution = .fillProportionally
|
||||
view.spacing = 0
|
||||
view.edgeInsets = NSEdgeInsets(
|
||||
self.spacing = Constants.Settings.margin
|
||||
self.edgeInsets = NSEdgeInsets(
|
||||
top: Constants.Settings.margin,
|
||||
left: Constants.Settings.margin,
|
||||
bottom: Constants.Settings.margin,
|
||||
right: Constants.Settings.margin
|
||||
)
|
||||
|
||||
let titleView = NSTextField()
|
||||
titleView.isEditable = false
|
||||
titleView.isSelectable = false
|
||||
titleView.isBezeled = false
|
||||
titleView.wantsLayer = true
|
||||
titleView.textColor = .black
|
||||
titleView.backgroundColor = .clear
|
||||
titleView.canDrawSubviewsIntoLayer = true
|
||||
titleView.alignment = .natural
|
||||
titleView.font = NSFont.systemFont(ofSize: 18, weight: .light)
|
||||
titleView.stringValue = localizedString(self.config.pointee.name)
|
||||
let widgetSelector = WidgetSelectorView(module: self.config.pointee.name, widgets: self.widgets, stateCallback: self.loadWidget)
|
||||
|
||||
var toggleBtn: NSControl = NSControl()
|
||||
if #available(OSX 10.15, *) {
|
||||
let switchButton = NSSwitch()
|
||||
switchButton.state = enabled ? .on : .off
|
||||
switchButton.action = #selector(self.toggleEnable)
|
||||
switchButton.target = self
|
||||
|
||||
toggleBtn = switchButton
|
||||
} else {
|
||||
let button: NSButton = NSButton()
|
||||
button.setButtonType(.switch)
|
||||
button.state = enabled ? .on : .off
|
||||
button.title = ""
|
||||
button.action = #selector(self.toggleEnable)
|
||||
button.isBordered = false
|
||||
button.isTransparent = false
|
||||
button.target = self
|
||||
|
||||
toggleBtn = button
|
||||
}
|
||||
self.enableControl = toggleBtn
|
||||
|
||||
view.addArrangedSubview(titleView)
|
||||
view.addArrangedSubview(NSView())
|
||||
view.addArrangedSubview(toggleBtn)
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
private func body() -> NSStackView {
|
||||
let view: NSStackView = NSStackView()
|
||||
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.orientation = .vertical
|
||||
view.edgeInsets = NSEdgeInsets(
|
||||
top: Constants.Settings.margin,
|
||||
left: Constants.Settings.margin,
|
||||
bottom: Constants.Settings.margin,
|
||||
right: Constants.Settings.margin
|
||||
)
|
||||
view.spacing = Constants.Settings.margin
|
||||
|
||||
view.addArrangedSubview(WidgetSelectorView(module: self.config.pointee.name, widgets: self.widgets, stateCallback: self.loadWidget))
|
||||
view.addArrangedSubview(self.settings())
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
// MARK: - views
|
||||
|
||||
private func settings() -> NSView {
|
||||
let view: NSTabView = NSTabView(frame: NSRect(x: 0, y: 0,
|
||||
width: Constants.Settings.width - Constants.Settings.margin*2,
|
||||
height: Constants.Settings.height - 40 - Constants.Widget.height - (Constants.Settings.margin*5)
|
||||
))
|
||||
view.widthAnchor.constraint(equalToConstant: view.frame.width).isActive = true
|
||||
view.heightAnchor.constraint(equalToConstant: view.frame.height).isActive = true
|
||||
view.tabViewType = .topTabsBezelBorder
|
||||
view.tabViewBorderType = .line
|
||||
let tabView = NSTabView()
|
||||
tabView.tabViewType = .topTabsBezelBorder
|
||||
tabView.tabViewBorderType = .line
|
||||
|
||||
let moduleTab: NSTabViewItem = NSTabViewItem()
|
||||
moduleTab.label = localizedString("Module settings")
|
||||
moduleTab.view = {
|
||||
let view = ScrollableStackView(frame: view.frame)
|
||||
self.moduleSettingsContainer = view.stackView
|
||||
let container = NSStackView()
|
||||
container.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
let scrollView = ScrollableStackView()
|
||||
self.moduleSettingsContainer = scrollView.stackView
|
||||
self.loadModuleSettings()
|
||||
return view
|
||||
|
||||
container.addArrangedSubview(scrollView)
|
||||
return container
|
||||
}()
|
||||
|
||||
let widgetTab: NSTabViewItem = NSTabViewItem()
|
||||
widgetTab.label = localizedString("Widget settings")
|
||||
widgetTab.view = {
|
||||
let view = ScrollableStackView(frame: view.frame)
|
||||
let view = ScrollableStackView(frame: tabView.frame)
|
||||
view.stackView.spacing = 0
|
||||
self.widgetSettingsContainer = view.stackView
|
||||
self.loadWidgetSettings()
|
||||
@@ -200,34 +96,27 @@ open class Settings: NSStackView, Settings_p {
|
||||
let popupTab: NSTabViewItem = NSTabViewItem()
|
||||
popupTab.label = localizedString("Popup settings")
|
||||
popupTab.view = {
|
||||
let view = ScrollableStackView(frame: view.frame)
|
||||
let view = ScrollableStackView(frame: tabView.frame)
|
||||
view.stackView.spacing = 0
|
||||
self.popupSettingsContainer = view.stackView
|
||||
self.loadPopupSettings()
|
||||
return view
|
||||
}()
|
||||
|
||||
view.addTabViewItem(moduleTab)
|
||||
view.addTabViewItem(widgetTab)
|
||||
view.addTabViewItem(popupTab)
|
||||
tabView.addTabViewItem(moduleTab)
|
||||
tabView.addTabViewItem(widgetTab)
|
||||
tabView.addTabViewItem(popupTab)
|
||||
|
||||
return view
|
||||
self.addArrangedSubview(widgetSelector)
|
||||
self.addArrangedSubview(tabView)
|
||||
}
|
||||
|
||||
// MARK: - helpers
|
||||
|
||||
@objc private func toggleEnable(_ sender: Any) {
|
||||
self.toggleCallback()
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
@objc private func externalModuleToggle(_ notification: Notification) {
|
||||
if let name = notification.userInfo?["module"] as? String {
|
||||
if name == self.config.pointee.name {
|
||||
if let state = notification.userInfo?["state"] as? Bool {
|
||||
toggleNSControlState(self.enableControl, state: state ? .on : .off)
|
||||
}
|
||||
}
|
||||
}
|
||||
required public init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
public func setState(_ newState: Bool) {
|
||||
@@ -249,7 +138,6 @@ open class Settings: NSStackView, Settings_p {
|
||||
self.moduleSettingsContainer?.addArrangedSubview(NSView())
|
||||
}
|
||||
}
|
||||
|
||||
private func loadWidgetSettings() {
|
||||
self.widgetSettingsContainer?.subviews.forEach{ $0.removeFromSuperview() }
|
||||
let list = self.widgets.filter({ $0.isActive && $0.type != .label })
|
||||
@@ -301,14 +189,7 @@ open class Settings: NSStackView, Settings_p {
|
||||
}
|
||||
|
||||
@objc private func toggleOneView(_ sender: NSControl) {
|
||||
var state: NSControl.StateValue? = nil
|
||||
if #available(OSX 10.15, *) {
|
||||
state = sender is NSSwitch ? (sender as! NSSwitch).state: nil
|
||||
} else {
|
||||
state = sender is NSButton ? (sender as! NSButton).state: nil
|
||||
}
|
||||
|
||||
self.oneViewState = state! == .on ? true : false
|
||||
self.oneViewState = controlState(sender)
|
||||
NotificationCenter.default.post(name: .toggleOneView, object: nil, userInfo: ["module": self.config.pointee.name])
|
||||
}
|
||||
}
|
||||
@@ -317,15 +198,26 @@ class WidgetSelectorView: NSStackView {
|
||||
private var module: String
|
||||
private var stateCallback: () -> Void = {}
|
||||
|
||||
private var background: NSVisualEffectView = {
|
||||
let view = NSVisualEffectView(frame: NSRect.zero)
|
||||
view.blendingMode = .withinWindow
|
||||
if #available(macOS 10.14, *) {
|
||||
view.material = .contentBackground
|
||||
} else {
|
||||
view.material = .popover
|
||||
}
|
||||
view.state = .active
|
||||
return view
|
||||
}()
|
||||
|
||||
public init(module: String, widgets: [Widget], stateCallback: @escaping () -> Void) {
|
||||
self.module = module
|
||||
self.stateCallback = stateCallback
|
||||
|
||||
super.init(frame: NSRect(x: 0, y: 0, width: 0, height: 0))
|
||||
super.init(frame: NSRect.zero)
|
||||
|
||||
self.translatesAutoresizingMaskIntoConstraints = false
|
||||
self.wantsLayer = true
|
||||
self.layer?.backgroundColor = .white
|
||||
self.layer?.cornerRadius = 3
|
||||
self.edgeInsets = NSEdgeInsets(
|
||||
top: Constants.Settings.margin,
|
||||
@@ -375,6 +267,7 @@ class WidgetSelectorView: NSStackView {
|
||||
}
|
||||
|
||||
self.addArrangedSubview(NSView())
|
||||
self.addSubview(self.background, positioned: .below, relativeTo: .none)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
self.heightAnchor.constraint(equalToConstant: Constants.Widget.height + (Constants.Settings.margin*2)),
|
||||
@@ -387,6 +280,10 @@ class WidgetSelectorView: NSStackView {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func updateLayer() {
|
||||
self.background.setFrameSize(self.frame.size)
|
||||
}
|
||||
|
||||
override func mouseDown(with event: NSEvent) {
|
||||
let location = convert(event.locationInWindow, from: nil)
|
||||
guard let targetIdx = self.views.firstIndex(where: { $0.hitTest(location) != nil }),
|
||||
@@ -501,6 +398,7 @@ internal class WidgetPreview: NSStackView {
|
||||
self.layer?.cornerRadius = 2
|
||||
self.layer?.borderColor = NSColor(hexString: "#dddddd").cgColor
|
||||
self.layer?.borderWidth = 1
|
||||
self.layer?.backgroundColor = NSColor.white.cgColor
|
||||
|
||||
self.identifier = NSUserInterfaceItemIdentifier(rawValue: type.rawValue)
|
||||
self.toolTip = localizedString("Move widget", type.name())
|
||||
|
||||
@@ -25,11 +25,9 @@ class Dashboard: NSScrollView {
|
||||
|
||||
self.drawsBackground = false
|
||||
self.borderType = .noBorder
|
||||
self.scrollerStyle = .overlay
|
||||
self.hasVerticalScroller = true
|
||||
self.hasHorizontalScroller = false
|
||||
self.autohidesScrollers = true
|
||||
self.horizontalScrollElasticity = .none
|
||||
self.automaticallyAdjustsContentInsets = false
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(windowOpens), name: .openModuleSettings, object: nil)
|
||||
|
||||
@@ -56,8 +54,10 @@ class Dashboard: NSScrollView {
|
||||
grid.row(at: 2).height = specsView.frame.height
|
||||
|
||||
self.documentView = grid
|
||||
if let documentView = self.documentView {
|
||||
documentView.scroll(NSPoint(x: 0, y: documentView.bounds.size.height))
|
||||
DispatchQueue.main.async {
|
||||
if let documentView = self.documentView {
|
||||
documentView.scroll(NSPoint(x: 0, y: documentView.bounds.size.height))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ class Dashboard: NSScrollView {
|
||||
}
|
||||
|
||||
private func versions() -> NSView {
|
||||
let view: NSView = NSView(frame: NSRect(x: 0, y: 0, width: self.frame.width, height: 280))
|
||||
let view: NSView = NSView(frame: NSRect(x: 0, y: 0, width: self.frame.width, height: 220))
|
||||
|
||||
let h: CGFloat = 120+60+18
|
||||
let container: NSGridView = NSGridView(frame: NSRect(x: 0, y: (view.frame.height-h)/2, width: self.frame.width, height: h))
|
||||
|
||||
@@ -12,9 +12,21 @@
|
||||
import Cocoa
|
||||
import Kit
|
||||
|
||||
class SettingsWindow: NSWindow, NSWindowDelegate {
|
||||
public extension NSToolbarItem.Identifier {
|
||||
static let toggleButton = NSToolbarItem.Identifier("toggleButton")
|
||||
}
|
||||
|
||||
class SettingsWindow: NSWindow, NSWindowDelegate, NSToolbarDelegate {
|
||||
static let size: CGSize = CGSize(width: 720, height: 480)
|
||||
private let vc: SettingsView = SettingsView()
|
||||
|
||||
private let mainView: MainView = MainView(frame: NSRect(x: 0, y: 0, width: 540, height: 480))
|
||||
private let sidebarView: SidebarView = SidebarView(frame: NSRect(x: 0, y: 0, width: 180, height: 480))
|
||||
|
||||
private var dashboard: NSView = Dashboard()
|
||||
private var settings: ApplicationSettings = ApplicationSettings()
|
||||
|
||||
private var toggleButton: NSControl? = nil
|
||||
private var activeModuleName: String? = nil
|
||||
|
||||
private var pauseState: Bool {
|
||||
Store.shared.bool(key: "pause", defaultValue: false)
|
||||
@@ -33,29 +45,59 @@ class SettingsWindow: NSWindow, NSWindowDelegate {
|
||||
defer: false
|
||||
)
|
||||
|
||||
self.contentViewController = self.vc
|
||||
self.titlebarAppearsTransparent = true
|
||||
self.backgroundColor = .clear
|
||||
self.center()
|
||||
self.setIsVisible(false)
|
||||
let sidebarViewController = NSSplitViewController()
|
||||
|
||||
let windowController = NSWindowController()
|
||||
windowController.window = self
|
||||
windowController.loadWindow()
|
||||
let sidebarVC: NSViewController = NSViewController(nibName: nil, bundle: nil)
|
||||
sidebarVC.view = self.sidebarView
|
||||
let mainVC: NSViewController = NSViewController(nibName: nil, bundle: nil)
|
||||
mainVC.view = self.mainView
|
||||
|
||||
let sidebarItem = NSSplitViewItem(sidebarWithViewController: sidebarVC)
|
||||
let contentItem = NSSplitViewItem(viewController: mainVC)
|
||||
|
||||
sidebarItem.canCollapse = false
|
||||
contentItem.canCollapse = false
|
||||
|
||||
sidebarViewController.addSplitViewItem(sidebarItem)
|
||||
sidebarViewController.addSplitViewItem(contentItem)
|
||||
|
||||
let newToolbar = NSToolbar(identifier: "eu.exelban.Stats.Settings.Toolbar")
|
||||
newToolbar.allowsUserCustomization = false
|
||||
newToolbar.autosavesConfiguration = true
|
||||
newToolbar.displayMode = .default
|
||||
newToolbar.showsBaselineSeparator = true
|
||||
newToolbar.delegate = self
|
||||
|
||||
self.toolbar = newToolbar
|
||||
self.contentViewController = sidebarViewController
|
||||
self.titlebarAppearsTransparent = true
|
||||
self.backgroundColor = .clear
|
||||
// self.center()
|
||||
self.setIsVisible(true)
|
||||
|
||||
let windowController = NSWindowController()
|
||||
windowController.window = self
|
||||
windowController.loadWindow()
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
self.sidebarView.widthAnchor.constraint(equalToConstant: 180),
|
||||
self.mainView.widthAnchor.constraint(equalToConstant: 540),
|
||||
self.mainView.container.widthAnchor.constraint(equalToConstant: 540),
|
||||
self.mainView.container.topAnchor.constraint(equalTo: (self.contentLayoutGuide as! NSLayoutGuide).topAnchor),
|
||||
self.mainView.container.bottomAnchor.constraint(equalTo: (self.contentLayoutGuide as! NSLayoutGuide).bottomAnchor)
|
||||
])
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(menuCallback), name: .openModuleSettings, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(toggleSettingsHandler), name: .toggleSettings, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(externalModuleToggle), name: .toggleModule, object: nil)
|
||||
|
||||
self.sidebarView.openMenu("Dashboard")
|
||||
}
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self, name: .toggleSettings, object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: .openModuleSettings, object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: .toggleModule, object: nil)
|
||||
}
|
||||
|
||||
override func performKeyEquivalent(with event: NSEvent) -> Bool {
|
||||
@@ -68,10 +110,55 @@ class SettingsWindow: NSWindow, NSWindowDelegate {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return super.performKeyEquivalent(with: event)
|
||||
}
|
||||
|
||||
override func mouseUp(with: NSEvent) {
|
||||
NotificationCenter.default.post(name: .clickInSettings, object: nil, userInfo: nil)
|
||||
}
|
||||
|
||||
func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? {
|
||||
switch itemIdentifier {
|
||||
case .toggleButton:
|
||||
var toggleBtn: NSControl = NSControl()
|
||||
if #available(OSX 10.15, *) {
|
||||
let switchButton = NSSwitch()
|
||||
switchButton.state = .on
|
||||
switchButton.action = #selector(self.toggleEnable)
|
||||
switchButton.target = self
|
||||
toggleBtn = switchButton
|
||||
} else {
|
||||
let button: NSButton = NSButton()
|
||||
button.setButtonType(.switch)
|
||||
button.state = .on
|
||||
button.title = ""
|
||||
button.action = #selector(self.toggleEnable)
|
||||
button.isBordered = false
|
||||
button.isTransparent = false
|
||||
button.target = self
|
||||
toggleBtn = button
|
||||
}
|
||||
self.toggleButton = toggleBtn
|
||||
|
||||
let toolbarItem = NSToolbarItem(itemIdentifier: itemIdentifier)
|
||||
toolbarItem.label = "Toggle the module"
|
||||
toolbarItem.paletteLabel = "Toggle the module"
|
||||
toolbarItem.toolTip = "Toggle the module"
|
||||
toolbarItem.view = toggleBtn
|
||||
|
||||
return toolbarItem
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
|
||||
return [.flexibleSpace, .toggleButton]
|
||||
}
|
||||
func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
|
||||
return [.flexibleSpace, .toggleButton]
|
||||
}
|
||||
|
||||
@objc private func toggleSettingsHandler(_ notification: Notification) {
|
||||
if !self.isVisible {
|
||||
self.setIsVisible(true)
|
||||
@@ -82,112 +169,102 @@ class SettingsWindow: NSWindow, NSWindowDelegate {
|
||||
}
|
||||
|
||||
if let name = notification.userInfo?["module"] as? String {
|
||||
self.vc.openMenu(name)
|
||||
self.sidebarView.openMenu(name)
|
||||
}
|
||||
}
|
||||
|
||||
public func setModules() {
|
||||
self.vc.setModules(modules)
|
||||
if !self.pauseState && modules.filter({ $0.enabled != false && $0.available != false && !$0.menuBar.widgets.filter({ $0.isActive }).isEmpty }).isEmpty {
|
||||
self.setIsVisible(true)
|
||||
}
|
||||
}
|
||||
|
||||
public func openMenu(_ title: String) {
|
||||
self.vc.openMenu(title)
|
||||
}
|
||||
|
||||
override func mouseUp(with: NSEvent) {
|
||||
NotificationCenter.default.post(name: .clickInSettings, object: nil, userInfo: nil)
|
||||
}
|
||||
}
|
||||
|
||||
private class SettingsView: NSSplitViewController {
|
||||
private var modules: [Module] = []
|
||||
|
||||
private let split: NSSplitView = SplitView()
|
||||
|
||||
private let sidebar: SidebarView = SidebarView(frame: NSRect(x: 0, y: 0, width: 180, height: 480))
|
||||
private let main: MainView = MainView(frame: NSRect(x: 0, y: 0, width: 540, height: 480))
|
||||
|
||||
private var dashboard: NSView = Dashboard()
|
||||
private var settings: ApplicationSettings = ApplicationSettings()
|
||||
|
||||
init() {
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
self.splitView = self.split
|
||||
|
||||
let sidebarVC: NSViewController = NSViewController(nibName: nil, bundle: nil)
|
||||
sidebarVC.view = self.sidebar
|
||||
let mainVC: NSViewController = NSViewController(nibName: nil, bundle: nil)
|
||||
mainVC.view = self.main
|
||||
|
||||
let sidebarItem = NSSplitViewItem(sidebarWithViewController: sidebarVC)
|
||||
let contentItem = NSSplitViewItem(viewController: mainVC)
|
||||
|
||||
self.addSplitViewItem(sidebarItem)
|
||||
self.addSplitViewItem(contentItem)
|
||||
|
||||
self.splitViewItems[0].canCollapse = false
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(menuCallback), name: .openModuleSettings, object: nil)
|
||||
|
||||
self.openMenu("Dashboard")
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
public func openMenu(_ title: String) {
|
||||
self.sidebar.openMenu(title)
|
||||
}
|
||||
|
||||
public func setModules(_ list: [Module]) {
|
||||
self.sidebar.setModules(list)
|
||||
self.modules = list
|
||||
}
|
||||
|
||||
@objc private func menuCallback(_ notification: Notification) {
|
||||
if let title = notification.userInfo?["module"] as? String {
|
||||
var view: NSView = NSView()
|
||||
if let detectedModule = self.modules.first(where: { $0.config.name == title }) {
|
||||
if let detectedModule = modules.first(where: { $0.config.name == title }) {
|
||||
if let v = detectedModule.settings {
|
||||
view = v
|
||||
}
|
||||
self.activeModuleName = detectedModule.config.name
|
||||
toggleNSControlState(self.toggleButton, state: detectedModule.enabled ? .on : .off)
|
||||
self.toggleButton?.isHidden = false
|
||||
} else if title == "Dashboard" {
|
||||
view = self.dashboard
|
||||
self.toggleButton?.isHidden = true
|
||||
} else if title == "Settings" {
|
||||
self.settings.viewWillAppear()
|
||||
view = self.settings
|
||||
self.toggleButton?.isHidden = true
|
||||
}
|
||||
|
||||
self.main.setView(view)
|
||||
self.sidebar.openMenu(title)
|
||||
self.title = localizedString(title)
|
||||
|
||||
self.mainView.setView(view)
|
||||
self.sidebarView.openMenu(title)
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func toggleEnable(_ sender: NSControl) {
|
||||
guard let moduleName = self.activeModuleName else { return }
|
||||
NotificationCenter.default.post(name: .toggleModule, object: nil, userInfo: ["module": moduleName, "state": controlState(sender)])
|
||||
}
|
||||
|
||||
@objc private func externalModuleToggle(_ notification: Notification) {
|
||||
if let name = notification.userInfo?["module"] as? String, name == self.activeModuleName {
|
||||
if let state = notification.userInfo?["state"] as? Bool {
|
||||
toggleNSControlState(self.toggleButton, state: state ? .on : .off)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func setModules() {
|
||||
self.sidebarView.setModules(modules)
|
||||
if !self.pauseState && modules.filter({ $0.enabled != false && $0.available != false && !$0.menuBar.widgets.filter({ $0.isActive }).isEmpty }).isEmpty {
|
||||
self.setIsVisible(true)
|
||||
}
|
||||
self.sidebarView.openMenu("Network")
|
||||
}
|
||||
}
|
||||
|
||||
private class SplitView: NSSplitView, NSSplitViewDelegate {
|
||||
init() {
|
||||
// MARK: - MainView
|
||||
|
||||
private class MainView: NSView {
|
||||
public let container: NSStackView
|
||||
|
||||
override init(frame: NSRect) {
|
||||
self.container = NSStackView(frame: NSRect(x: 0, y: 0, width: frame.width, height: frame.height))
|
||||
|
||||
let foreground = NSVisualEffectView(frame: NSRect(x: 0, y: 0, width: frame.width, height: frame.height))
|
||||
foreground.blendingMode = .withinWindow
|
||||
if #available(macOS 10.14, *) {
|
||||
foreground.material = .windowBackground
|
||||
} else {
|
||||
foreground.material = .popover
|
||||
}
|
||||
foreground.state = .active
|
||||
|
||||
super.init(frame: NSRect.zero)
|
||||
|
||||
self.isVertical = true
|
||||
self.delegate = self
|
||||
self.container.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
self.widthAnchor.constraint(equalToConstant: SettingsWindow.size.width).isActive = true
|
||||
self.heightAnchor.constraint(equalToConstant: SettingsWindow.size.height).isActive = true
|
||||
self.addSubview(foreground, positioned: .below, relativeTo: .none)
|
||||
self.addSubview(self.container)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func cursorUpdate(with event: NSEvent) {
|
||||
NSCursor.arrow.set()
|
||||
public func setView(_ view: NSView) {
|
||||
self.container.subviews.forEach{ $0.removeFromSuperview() }
|
||||
self.container.addArrangedSubview(view)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
view.leftAnchor.constraint(equalTo: self.container.leftAnchor),
|
||||
view.rightAnchor.constraint(equalTo: self.container.rightAnchor),
|
||||
view.topAnchor.constraint(equalTo: self.container.topAnchor),
|
||||
view.bottomAnchor.constraint(equalTo: self.container.bottomAnchor)
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Sidebar
|
||||
|
||||
private class SidebarView: NSStackView {
|
||||
private let scrollView: ScrollableStackView
|
||||
|
||||
@@ -433,31 +510,3 @@ private class MenuItem: NSView {
|
||||
self.active = false
|
||||
}
|
||||
}
|
||||
|
||||
private class MainView: NSView {
|
||||
override init(frame: NSRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
self.wantsLayer = true
|
||||
|
||||
let foreground = NSVisualEffectView(frame: NSRect(x: 0, y: 0, width: frame.width, height: frame.height))
|
||||
foreground.blendingMode = .withinWindow
|
||||
if #available(macOS 10.14, *) {
|
||||
foreground.material = .windowBackground
|
||||
} else {
|
||||
foreground.material = .popover
|
||||
}
|
||||
foreground.state = .active
|
||||
|
||||
self.addSubview(foreground, positioned: .below, relativeTo: .none)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
public func setView(_ view: NSView) {
|
||||
self.subviews.filter{ !($0 is NSVisualEffectView) }.forEach{ $0.removeFromSuperview() }
|
||||
self.addSubview(view)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user