mirror of
https://github.com/morgan9e/macos-stats
synced 2026-04-15 00:34:08 +09:00
feat: renamed internal class Settings to Window (preparation for in-app statistics view)
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
import Cocoa
|
||||
|
||||
public struct module_c {
|
||||
public var name: String = ""
|
||||
public var name: String
|
||||
public var icon: NSImage?
|
||||
|
||||
public var defaultState: Bool = false
|
||||
@@ -18,13 +18,19 @@ public struct module_c {
|
||||
|
||||
internal var widgetsConfig: NSDictionary = NSDictionary()
|
||||
internal var settingsConfig: NSDictionary = NSDictionary()
|
||||
internal var previewConfig: NSDictionary = NSDictionary()
|
||||
|
||||
public var hasPreview: Bool { self.previewConfig["enabled"] as? Bool ?? false }
|
||||
|
||||
init(in path: String) {
|
||||
let dict: NSDictionary = NSDictionary(contentsOfFile: path)!
|
||||
|
||||
if let name = dict["Name"] as? String {
|
||||
self.name = name
|
||||
} else {
|
||||
fatalError("failed to initialize module, name is missing")
|
||||
}
|
||||
|
||||
if let state = dict["State"] as? Bool {
|
||||
self.defaultState = state
|
||||
}
|
||||
@@ -60,6 +66,10 @@ public struct module_c {
|
||||
if let settingsDict = dict["Settings"] as? NSDictionary {
|
||||
self.settingsConfig = settingsDict
|
||||
}
|
||||
|
||||
if let previewDict = dict["Preview"] as? NSDictionary {
|
||||
self.previewConfig = previewDict
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +80,7 @@ open class Module {
|
||||
public var enabled: Bool = false
|
||||
|
||||
public var menuBar: MenuBar
|
||||
public var settings: Settings_p? = nil
|
||||
public var window: Window? = nil
|
||||
public let portal: Portal_p?
|
||||
|
||||
public var name: String { config.name }
|
||||
@@ -88,6 +98,7 @@ open class Module {
|
||||
private var popup: PopupWindow? = nil
|
||||
private var popupView: Popup_p? = nil
|
||||
private var notificationsView: NotificationsWrapper? = nil
|
||||
private var previewView: Preview_v? = nil
|
||||
|
||||
private let log: NextLog
|
||||
private var readers: [Reader_p] = []
|
||||
@@ -97,7 +108,14 @@ open class Module {
|
||||
set { Store.shared.set(key: "pause", value: newValue) }
|
||||
}
|
||||
|
||||
public init(moduleType: ModuleType, popup: Popup_p? = nil, settings: Settings_v? = nil, portal: Portal_p? = nil, notifications: NotificationsWrapper? = nil) {
|
||||
public init(
|
||||
moduleType: ModuleType,
|
||||
popup: Popup_p? = nil,
|
||||
settings: Settings_v? = nil,
|
||||
portal: Portal_p? = nil,
|
||||
notifications: NotificationsWrapper? = nil,
|
||||
preview: Preview_v? = nil
|
||||
) {
|
||||
self.moduleType = moduleType
|
||||
self.portal = portal
|
||||
self.config = module_c(in: Bundle(for: type(of: self)).path(forResource: "config", ofType: "plist")!)
|
||||
@@ -106,6 +124,7 @@ open class Module {
|
||||
self.settingsView = settings
|
||||
self.popupView = popup
|
||||
self.notificationsView = notifications
|
||||
self.previewView = preview
|
||||
self.menuBar = MenuBar(moduleName: self.config.name)
|
||||
self.available = self.isAvailable()
|
||||
self.enabled = Store.shared.bool(key: "\(self.config.name)_state", defaultValue: self.config.defaultState)
|
||||
@@ -128,6 +147,7 @@ open class Module {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(listenForModuleToggle), name: .toggleModule, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(listenForPopupToggle), name: .togglePopup, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(listenForToggleWidget), name: .toggleWidget, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(listenForWindowOpen), name: .openWindow, object: nil)
|
||||
|
||||
// swiftlint:disable empty_count
|
||||
if self.config.widgetsConfig.count != 0 {
|
||||
@@ -137,15 +157,16 @@ open class Module {
|
||||
debug("Module started without widget", log: self.log)
|
||||
}
|
||||
|
||||
self.settings = Settings(
|
||||
self.window = Window(
|
||||
config: &self.config,
|
||||
widgets: &self.menuBar.widgets,
|
||||
modulePreview: self.previewView,
|
||||
moduleSettings: self.settingsView,
|
||||
popupSettings: self.popupView,
|
||||
notificationsSettings: self.notificationsView
|
||||
)
|
||||
|
||||
self.popup = PopupWindow(title: self.config.name, module: self.moduleType, view: self.popupView, visibilityCallback: self.visibilityCallback)
|
||||
self.popup = PopupWindow(title: self.config.name, module: self.moduleType, view: self.popupView, visibilityCallback: self.popupVisibilityCallback)
|
||||
}
|
||||
|
||||
deinit {
|
||||
@@ -194,7 +215,7 @@ open class Module {
|
||||
reader.start()
|
||||
}
|
||||
self.menuBar.enable()
|
||||
self.settings?.setState(self.enabled)
|
||||
self.window?.setState(self.enabled)
|
||||
debug("Module enabled", log: self.log)
|
||||
}
|
||||
|
||||
@@ -209,7 +230,7 @@ open class Module {
|
||||
}
|
||||
self.readers.forEach{ $0.stop() }
|
||||
self.menuBar.disable()
|
||||
self.settings?.setState(self.enabled)
|
||||
self.window?.setState(self.enabled)
|
||||
self.popup?.setIsVisible(false)
|
||||
debug("Module disabled", log: self.log)
|
||||
}
|
||||
@@ -237,8 +258,26 @@ open class Module {
|
||||
}
|
||||
|
||||
// call when popup appear/disappear
|
||||
private func visibilityCallback(_ state: Bool) {
|
||||
self.readers.filter{ $0.popup }.forEach { (reader: Reader_p) in
|
||||
private func popupVisibilityCallback(_ state: Bool) {
|
||||
self.readers.filter{ $0.popup || $0.sleep }.forEach { (reader: Reader_p) in
|
||||
if state {
|
||||
reader.unlock()
|
||||
reader.start()
|
||||
} else {
|
||||
reader.pause()
|
||||
reader.lock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func listenForWindowOpen(_ notification: Notification) {
|
||||
guard var state = notification.userInfo?["state"] as? Bool else { return }
|
||||
|
||||
if state, let name = notification.userInfo?["module"] as? String, self.config.name != name {
|
||||
state = false
|
||||
}
|
||||
|
||||
self.readers.filter{ $0.preview || $0.sleep }.forEach { (reader: Reader_p) in
|
||||
if state {
|
||||
reader.unlock()
|
||||
reader.start()
|
||||
|
||||
@@ -11,21 +11,20 @@
|
||||
|
||||
import Cocoa
|
||||
|
||||
public protocol Settings_p: NSView {
|
||||
func setState(_ newState: Bool)
|
||||
}
|
||||
|
||||
public protocol Settings_v: NSView {
|
||||
func load(widgets: [widget_t])
|
||||
}
|
||||
|
||||
open class Settings: NSStackView, Settings_p {
|
||||
public protocol Preview_v: NSView {}
|
||||
|
||||
open class Window: NSStackView {
|
||||
private var config: UnsafePointer<module_c>
|
||||
private var widgets: [SWidget]
|
||||
|
||||
private var segmentedControl: NSSegmentedControl?
|
||||
private var tabView: NSTabView?
|
||||
|
||||
private var modulePreview: Preview_v?
|
||||
private var moduleSettings: Settings_v?
|
||||
private var popupSettings: Popup_p?
|
||||
private var notificationsSettings: NotificationsWrapper?
|
||||
@@ -50,19 +49,30 @@ open class Settings: NSStackView, Settings_p {
|
||||
set { Store.shared.set(key: "\(self.config.pointee.name)_oneView", value: newValue) }
|
||||
}
|
||||
|
||||
private var isPreviewAvailable: Bool
|
||||
private var isPopupSettingsAvailable: Bool
|
||||
private var isNotificationsSettingsAvailable: Bool
|
||||
|
||||
private var previewView: NSView? = nil
|
||||
private var settingsView: NSView? = nil
|
||||
|
||||
init(config: UnsafePointer<module_c>, widgets: UnsafeMutablePointer<[SWidget]>, moduleSettings: Settings_v?, popupSettings: Popup_p?, notificationsSettings: NotificationsWrapper?) {
|
||||
init(
|
||||
config: UnsafePointer<module_c>,
|
||||
widgets: UnsafeMutablePointer<[SWidget]>,
|
||||
modulePreview: Preview_v?,
|
||||
moduleSettings: Settings_v?,
|
||||
popupSettings: Popup_p?,
|
||||
notificationsSettings: NotificationsWrapper?
|
||||
) {
|
||||
self.config = config
|
||||
self.widgets = widgets.pointee
|
||||
self.modulePreview = modulePreview
|
||||
self.moduleSettings = moduleSettings
|
||||
self.popupSettings = popupSettings
|
||||
self.notificationsSettings = notificationsSettings
|
||||
|
||||
self.isPreviewAvailable = config.pointee.previewConfig["enabled"] as? Bool ?? false
|
||||
|
||||
self.isPopupSettingsAvailable = config.pointee.settingsConfig["popup"] as? Bool ?? false
|
||||
self.isNotificationsSettingsAvailable = config.pointee.settingsConfig["notifications"] as? Bool ?? false
|
||||
|
||||
@@ -79,22 +89,27 @@ open class Settings: NSStackView, Settings_p {
|
||||
right: Constants.Settings.margin
|
||||
)
|
||||
|
||||
let header = self.header()
|
||||
let settingsView = self.settings()
|
||||
self.settingsView = settingsView
|
||||
let previewView = self.preview()
|
||||
self.previewView = previewView
|
||||
|
||||
self.addArrangedSubview(header)
|
||||
self.addArrangedSubview(settingsView)
|
||||
self.addArrangedSubview(previewView)
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(listenForOneView), name: .toggleOneView, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(listenForToggleView), name: .togglePreview, object: nil)
|
||||
|
||||
self.segmentedControl?.widthAnchor.constraint(equalTo: self.widthAnchor, constant: -(Constants.Settings.margin*2)).isActive = true
|
||||
|
||||
if self.isPreviewAvailable {
|
||||
self.toggleView()
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self, name: .toggleOneView, object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: .togglePreview, object: nil)
|
||||
}
|
||||
|
||||
required public init?(coder: NSCoder) {
|
||||
@@ -105,28 +120,20 @@ open class Settings: NSStackView, Settings_p {
|
||||
toggleNSControlState(self.enableControl, state: newState ? .on : .off)
|
||||
}
|
||||
|
||||
private func header() -> NSView {
|
||||
let view = NSStackView()
|
||||
view.orientation = .horizontal
|
||||
view.spacing = Constants.Settings.margin
|
||||
|
||||
let widgetSelector = WidgetSelectorView(module: self.config.pointee.name, widgets: self.widgets, stateCallback: self.loadWidget)
|
||||
// let button = ButtonSelectorView { [weak self] in
|
||||
// self?.toggleView()
|
||||
// }
|
||||
|
||||
view.addArrangedSubview(widgetSelector)
|
||||
// view.addArrangedSubview(button)
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
private func preview() -> NSView {
|
||||
let view = NSStackView()
|
||||
view.isHidden = true
|
||||
view.orientation = .vertical
|
||||
view.addArrangedSubview(EmptyView(height: 0, msg: localizedString("Preview is not available for that module")))
|
||||
return view
|
||||
let container = NSStackView()
|
||||
container.isHidden = true
|
||||
container.orientation = .vertical
|
||||
|
||||
var view: NSView = EmptyView(height: 0, msg: localizedString("Preview is not available for that module"))
|
||||
|
||||
if self.isPreviewAvailable, let v = self.modulePreview {
|
||||
view = v
|
||||
}
|
||||
|
||||
container.addArrangedSubview(view)
|
||||
|
||||
return container
|
||||
}
|
||||
|
||||
private func settings() -> NSView {
|
||||
@@ -208,6 +215,9 @@ open class Settings: NSStackView, Settings_p {
|
||||
tabView.addTabViewItem(notificationsTab)
|
||||
}
|
||||
|
||||
let widgetSelector = WidgetSelectorView(module: self.config.pointee.name, widgets: self.widgets, stateCallback: self.loadWidget)
|
||||
|
||||
view.addArrangedSubview(widgetSelector)
|
||||
view.addArrangedSubview(segmentedControl)
|
||||
view.addArrangedSubview(tabView)
|
||||
|
||||
@@ -296,9 +306,12 @@ open class Settings: NSStackView, Settings_p {
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func toggleView() {
|
||||
@objc private func listenForToggleView(_ notification: Notification) {
|
||||
guard let moduleName = notification.userInfo?["module"], self.config.pointee.name == moduleName as? String else { return }
|
||||
self.toggleView()
|
||||
}
|
||||
private func toggleView() {
|
||||
guard let preview = self.previewView, let settings = self.settingsView else { return }
|
||||
|
||||
preview.isHidden = !preview.isHidden
|
||||
settings.isHidden = !settings.isHidden
|
||||
}
|
||||
@@ -310,7 +323,7 @@ private class WidgetSelectorView: NSStackView {
|
||||
private var moved: Bool = false
|
||||
|
||||
private var background: NSVisualEffectView = {
|
||||
let view = NSVisualEffectView(frame: NSRect.zero)
|
||||
let view = NSVisualEffectView(frame: .zero)
|
||||
view.blendingMode = .withinWindow
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
if #available(macOS 26.0, *) {
|
||||
@@ -666,80 +679,3 @@ private class WidgetSettings: NSStackView {
|
||||
return container
|
||||
}
|
||||
}
|
||||
|
||||
private class ButtonSelectorView: NSStackView {
|
||||
private var callback: () -> Void
|
||||
|
||||
private var background: NSVisualEffectView = {
|
||||
let view = NSVisualEffectView(frame: NSRect.zero)
|
||||
view.blendingMode = .withinWindow
|
||||
view.material = .contentBackground
|
||||
view.state = .active
|
||||
view.wantsLayer = true
|
||||
view.layer?.cornerRadius = 5
|
||||
return view
|
||||
}()
|
||||
|
||||
private var settingsIcon: NSImage { iconFromSymbol(name: "gear", scale: .large) }
|
||||
private var previewIcon: NSImage { iconFromSymbol(name: "command", scale: .large) }
|
||||
|
||||
private var button: NSButton? = nil
|
||||
private var isSettingsEnabled: Bool = false
|
||||
|
||||
fileprivate init(callback: @escaping () -> Void) {
|
||||
self.callback = callback
|
||||
|
||||
super.init(frame: NSRect.zero)
|
||||
|
||||
self.heightAnchor.constraint(equalToConstant: Constants.Widget.height + (Constants.Settings.margin*2)).isActive = true
|
||||
self.translatesAutoresizingMaskIntoConstraints = false
|
||||
self.edgeInsets = NSEdgeInsets(
|
||||
top: Constants.Settings.margin,
|
||||
left: Constants.Settings.margin,
|
||||
bottom: Constants.Settings.margin,
|
||||
right: Constants.Settings.margin
|
||||
)
|
||||
self.spacing = Constants.Settings.margin
|
||||
|
||||
self.addSubview(self.background, positioned: .below, relativeTo: .none)
|
||||
|
||||
let button = NSButton()
|
||||
button.toolTip = localizedString("Open module settings")
|
||||
button.bezelStyle = .regularSquare
|
||||
button.translatesAutoresizingMaskIntoConstraints = false
|
||||
button.imageScaling = .scaleNone
|
||||
button.image = self.settingsIcon
|
||||
button.contentTintColor = .secondaryLabelColor
|
||||
button.isBordered = false
|
||||
button.action = #selector(self.action)
|
||||
button.target = self
|
||||
button.focusRingType = .none
|
||||
button.widthAnchor.constraint(equalToConstant: Constants.Widget.height).isActive = true
|
||||
self.button = button
|
||||
|
||||
self.addArrangedSubview(button)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func updateLayer() {
|
||||
self.background.setFrameSize(self.frame.size)
|
||||
}
|
||||
|
||||
@objc private func action() {
|
||||
guard let button = self.button else { return }
|
||||
self.callback()
|
||||
|
||||
self.isSettingsEnabled = !self.isSettingsEnabled
|
||||
|
||||
if self.isSettingsEnabled {
|
||||
button.image = self.previewIcon
|
||||
button.toolTip = localizedString("Close module settings")
|
||||
} else {
|
||||
button.image = self.settingsIcon
|
||||
button.toolTip = localizedString("Open module settings")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ public class ProcessesView: NSStackView {
|
||||
private var list: [ProcessView] = []
|
||||
private var colorViews: [ColorView] = []
|
||||
|
||||
public init(frame: NSRect, values: [ProcessHeader], n: Int = 0) {
|
||||
public init(frame: NSRect = .zero, values: [ProcessHeader], n: Int = 0) {
|
||||
super.init(frame: frame)
|
||||
|
||||
self.orientation = .vertical
|
||||
|
||||
@@ -266,6 +266,7 @@ public extension Notification.Name {
|
||||
static let toggleModule = Notification.Name("toggleModule")
|
||||
static let togglePopup = Notification.Name("togglePopup")
|
||||
static let toggleWidget = Notification.Name("toggleWidget")
|
||||
static let togglePreview = Notification.Name("togglePreview")
|
||||
static let openModuleSettings = Notification.Name("openModuleSettings")
|
||||
static let clickInSettings = Notification.Name("clickInSettings")
|
||||
static let refreshPublicIP = Notification.Name("refreshPublicIP")
|
||||
@@ -281,6 +282,7 @@ public extension Notification.Name {
|
||||
static let combinedModulesPopup = Notification.Name("combinedModulesPopup")
|
||||
static let remoteLoginSuccess = Notification.Name("remoteLoginSuccess")
|
||||
static let remoteState = Notification.Name("remoteState")
|
||||
static let openWindow = Notification.Name("openWindow")
|
||||
}
|
||||
|
||||
public var isARM: Bool {
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
9A2847672666AA2700EC1F6D /* BarChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A28475D2666AA2700EC1F6D /* BarChart.swift */; };
|
||||
9A2847682666AA2700EC1F6D /* Stack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A28475E2666AA2700EC1F6D /* Stack.swift */; };
|
||||
9A2847792666AA5000EC1F6D /* module.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A2847742666AA5000EC1F6D /* module.swift */; };
|
||||
9A28477A2666AA5000EC1F6D /* settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A2847752666AA5000EC1F6D /* settings.swift */; };
|
||||
9A28477A2666AA5000EC1F6D /* window.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A2847752666AA5000EC1F6D /* window.swift */; };
|
||||
9A28477B2666AA5000EC1F6D /* popup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A2847762666AA5000EC1F6D /* popup.swift */; };
|
||||
9A28477C2666AA5000EC1F6D /* reader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A2847772666AA5000EC1F6D /* reader.swift */; };
|
||||
9A28477D2666AA5000EC1F6D /* widget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A2847782666AA5000EC1F6D /* widget.swift */; };
|
||||
@@ -603,7 +603,7 @@
|
||||
9A28475D2666AA2700EC1F6D /* BarChart.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BarChart.swift; sourceTree = "<group>"; };
|
||||
9A28475E2666AA2700EC1F6D /* Stack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Stack.swift; sourceTree = "<group>"; };
|
||||
9A2847742666AA5000EC1F6D /* module.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = module.swift; sourceTree = "<group>"; };
|
||||
9A2847752666AA5000EC1F6D /* settings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = settings.swift; sourceTree = "<group>"; };
|
||||
9A2847752666AA5000EC1F6D /* window.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = window.swift; sourceTree = "<group>"; };
|
||||
9A2847762666AA5000EC1F6D /* popup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = popup.swift; sourceTree = "<group>"; };
|
||||
9A2847772666AA5000EC1F6D /* reader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = reader.swift; sourceTree = "<group>"; };
|
||||
9A2847782666AA5000EC1F6D /* widget.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = widget.swift; sourceTree = "<group>"; };
|
||||
@@ -1060,7 +1060,7 @@
|
||||
9A2847762666AA5000EC1F6D /* popup.swift */,
|
||||
9A2847782666AA5000EC1F6D /* widget.swift */,
|
||||
9A2847772666AA5000EC1F6D /* reader.swift */,
|
||||
9A2847752666AA5000EC1F6D /* settings.swift */,
|
||||
9A2847752666AA5000EC1F6D /* window.swift */,
|
||||
5C23BC0329A014AC00DBA990 /* portal.swift */,
|
||||
5CF2210C2B1E7EAF006C583F /* notifications.swift */,
|
||||
);
|
||||
@@ -2095,7 +2095,7 @@
|
||||
9A28477D2666AA5000EC1F6D /* widget.swift in Sources */,
|
||||
9A2848212666AB3600EC1F6D /* helpers.swift in Sources */,
|
||||
5CAA50722C8E417700B13E13 /* Text.swift in Sources */,
|
||||
9A28477A2666AA5000EC1F6D /* settings.swift in Sources */,
|
||||
9A28477A2666AA5000EC1F6D /* window.swift in Sources */,
|
||||
9A28475F2666AA2700EC1F6D /* LineChart.swift in Sources */,
|
||||
9A302614286A2A3B00B41D57 /* Repeater.swift in Sources */,
|
||||
5C4E8BA12B6EEE8E00F148B6 /* lldb.m in Sources */,
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>756</string>
|
||||
<string>757</string>
|
||||
<key>Description</key>
|
||||
<string>Simple macOS system monitor in your menu bar</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
|
||||
@@ -14,6 +14,7 @@ import Kit
|
||||
|
||||
public extension NSToolbarItem.Identifier {
|
||||
static let toggleButton = NSToolbarItem.Identifier("toggleButton")
|
||||
static let previewButton = NSToolbarItem.Identifier("previewButton")
|
||||
}
|
||||
|
||||
class SettingsWindow: NSWindow, NSWindowDelegate, NSToolbarDelegate {
|
||||
@@ -28,6 +29,7 @@ class SettingsWindow: NSWindow, NSWindowDelegate, NSToolbarDelegate {
|
||||
|
||||
private var toggleButton: NSControl? = nil
|
||||
private var activeModuleName: String? = nil
|
||||
private var settingsPreviewButton: NSView? = nil
|
||||
|
||||
private var pauseState: Bool { Store.shared.bool(key: "pause", defaultValue: false) }
|
||||
|
||||
@@ -119,6 +121,18 @@ class SettingsWindow: NSWindow, NSWindowDelegate, NSToolbarDelegate {
|
||||
|
||||
func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? {
|
||||
switch itemIdentifier {
|
||||
case .previewButton:
|
||||
let button = SettingsPreviewButton { [weak self] in
|
||||
guard let moduleName = self?.activeModuleName else { return }
|
||||
NotificationCenter.default.post(name: .togglePreview, object: nil, userInfo: ["module": moduleName])
|
||||
}
|
||||
self.settingsPreviewButton = button
|
||||
|
||||
let toolbarItem = NSToolbarItem(itemIdentifier: itemIdentifier)
|
||||
toolbarItem.view = button
|
||||
toolbarItem.isBordered = false
|
||||
|
||||
return toolbarItem
|
||||
case .toggleButton:
|
||||
let switchButton = NSSwitch()
|
||||
switchButton.state = .on
|
||||
@@ -139,10 +153,10 @@ class SettingsWindow: NSWindow, NSWindowDelegate, NSToolbarDelegate {
|
||||
}
|
||||
|
||||
func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
|
||||
return [.flexibleSpace, .toggleButton]
|
||||
return [.flexibleSpace, .previewButton, .toggleButton]
|
||||
}
|
||||
func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
|
||||
return [.flexibleSpace, .toggleButton]
|
||||
return [.flexibleSpace, .previewButton, .toggleButton]
|
||||
}
|
||||
|
||||
@objc private func toggleSettingsHandler(_ notification: Notification) {
|
||||
@@ -164,19 +178,25 @@ class SettingsWindow: NSWindow, NSWindowDelegate, NSToolbarDelegate {
|
||||
if let title = notification.userInfo?["module"] as? String {
|
||||
var view: NSView = NSView()
|
||||
if let detectedModule = modules.first(where: { $0.config.name == title }) {
|
||||
if let v = detectedModule.settings {
|
||||
if let v = detectedModule.window {
|
||||
view = v
|
||||
}
|
||||
self.activeModuleName = detectedModule.config.name
|
||||
toggleNSControlState(self.toggleButton, state: detectedModule.enabled ? .on : .off)
|
||||
self.toggleButton?.isHidden = false
|
||||
self.settingsPreviewButton?.isHidden = !detectedModule.config.hasPreview
|
||||
NotificationCenter.default.post(name: .openWindow, object: nil, userInfo: ["module": detectedModule.config.name, "state": true])
|
||||
} else if title == "Dashboard" {
|
||||
view = self.dashboard
|
||||
self.toggleButton?.isHidden = true
|
||||
self.settingsPreviewButton?.isHidden = true
|
||||
NotificationCenter.default.post(name: .openWindow, object: nil, userInfo: ["state": false])
|
||||
} else if title == "Settings" {
|
||||
self.settings.viewWillAppear()
|
||||
view = self.settings
|
||||
self.toggleButton?.isHidden = true
|
||||
self.settingsPreviewButton?.isHidden = true
|
||||
NotificationCenter.default.post(name: .openWindow, object: nil, userInfo: ["state": false])
|
||||
}
|
||||
|
||||
self.title = localizedString(title)
|
||||
@@ -523,3 +543,63 @@ private class MenuItem: NSView {
|
||||
self.active = false
|
||||
}
|
||||
}
|
||||
|
||||
private class SettingsPreviewButton: NSStackView {
|
||||
private var callback: () -> Void
|
||||
|
||||
private var settingsIcon: NSImage { iconFromSymbol(name: "gear", scale: .large) }
|
||||
private var previewIcon: NSImage { iconFromSymbol(name: "command", scale: .large) }
|
||||
|
||||
private var button: NSButton? = nil
|
||||
private var isSettingsEnabled: Bool = false
|
||||
|
||||
fileprivate init(callback: @escaping () -> Void) {
|
||||
self.callback = callback
|
||||
|
||||
super.init(frame: .zero)
|
||||
|
||||
self.translatesAutoresizingMaskIntoConstraints = false
|
||||
self.edgeInsets = NSEdgeInsets(
|
||||
top: Constants.Settings.margin,
|
||||
left: Constants.Settings.margin,
|
||||
bottom: Constants.Settings.margin,
|
||||
right: Constants.Settings.margin
|
||||
)
|
||||
self.spacing = Constants.Settings.margin
|
||||
|
||||
let button = NSButton()
|
||||
button.toolTip = localizedString("Open module settings")
|
||||
button.bezelStyle = .regularSquare
|
||||
button.translatesAutoresizingMaskIntoConstraints = false
|
||||
button.imageScaling = .scaleNone
|
||||
button.image = self.settingsIcon
|
||||
button.contentTintColor = .secondaryLabelColor
|
||||
button.isBordered = false
|
||||
button.action = #selector(self.action)
|
||||
button.target = self
|
||||
button.focusRingType = .none
|
||||
button.widthAnchor.constraint(equalToConstant: Constants.Widget.height).isActive = true
|
||||
self.button = button
|
||||
|
||||
self.addArrangedSubview(button)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
@objc private func action() {
|
||||
guard let button = self.button else { return }
|
||||
self.callback()
|
||||
|
||||
self.isSettingsEnabled = !self.isSettingsEnabled
|
||||
|
||||
if self.isSettingsEnabled {
|
||||
button.image = self.previewIcon
|
||||
button.toolTip = localizedString("Close module settings")
|
||||
} else {
|
||||
button.image = self.settingsIcon
|
||||
button.toolTip = localizedString("Open module settings")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.12.3</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>756</string>
|
||||
<string>757</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
|
||||
Reference in New Issue
Block a user