- add option to show removable disks in Disk module

- add notification when popup view size must be recalculated
This commit is contained in:
Serhiy Mytrovtsiy
2020-07-06 20:34:29 +02:00
parent 5e51770cbc
commit cb8ab6365c
7 changed files with 93 additions and 14 deletions

View File

@@ -104,6 +104,7 @@ open class Module: Module_p {
NotificationCenter.default.addObserver(self, selector: #selector(listenForWidgetSwitch), name: .switchWidget, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(listenForMouseDownInSettings), name: .clickInSettings, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(listenForModuleToggle), name: .toggleModule, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(listenChangingPopupSize), name: .updatePopupSize, object: nil)
if self.config.widgetsConfig.count != 0 {
self.setWidget()
@@ -255,24 +256,25 @@ open class Module: Module_p {
self.settings?.setActiveWidget(self.widget)
}
@objc private func togglePopup(_ sender: NSStatusBarButton) {
@objc private func togglePopup(_ sender: Any) {
let openedWindows = NSApplication.shared.windows.filter{ $0 is NSPanel }
openedWindows.forEach{ $0.setIsVisible(false) }
if self.popup.occlusionState.rawValue == 8192 {
NSApplication.shared.activate(ignoringOtherApps: true)
self.popup.contentView?.invalidateIntrinsicContentSize()
let buttonOrigin = self.menuBarItem.button?.window?.frame.origin
let buttonCenter = (self.menuBarItem.button?.window?.frame.width)! / 2
let windowCenter = self.popup.frame.width / 2
self.popup.contentView?.invalidateIntrinsicContentSize()
let windowCenter = self.popup.contentView!.intrinsicContentSize.width / 2
var x = buttonOrigin!.x - windowCenter + buttonCenter
let y = buttonOrigin!.y - self.popup.contentView!.intrinsicContentSize.height - 3
let maxWidth = NSScreen.screens.map{ $0.frame.width }.reduce(0, +)
if x + self.popup.frame.width > maxWidth {
x = maxWidth - self.popup.frame.width - 3
if x + self.popup.contentView!.intrinsicContentSize.width > maxWidth {
x = maxWidth - self.popup.contentView!.intrinsicContentSize.width - 3
}
self.popup.setFrameOrigin(NSPoint(x: x, y: y))
@@ -314,4 +316,12 @@ open class Module: Module_p {
self.popup.setIsVisible(false)
}
}
@objc private func listenChangingPopupSize(_ notification: Notification) {
if let moduleName = notification.userInfo?["module"] as? String, moduleName == self.config.name {
if self.popup.isVisible {
self.popup.setIsVisible(false)
}
}
}
}

View File

@@ -69,6 +69,7 @@ internal class PopupViewController: NSViewController {
public func setup(title: String, view: NSView?) {
self.title = title
self.popup.title = title
self.popup.headerView?.titleView?.stringValue = title
self.popup.setView(view)
}
@@ -76,6 +77,7 @@ internal class PopupViewController: NSViewController {
internal class PopupView: NSView {
public var headerView: HeaderView? = nil
public var title: String? = nil
private var mainView: NSView? = nil
override var intrinsicContentSize: CGSize {
@@ -92,6 +94,7 @@ internal class PopupView: NSView {
self.canDrawConcurrently = true
self.layer!.cornerRadius = 3
NotificationCenter.default.addObserver(self, selector: #selector(listenChangingPopupSize), name: .updatePopupSize, object: nil)
self.headerView = HeaderView(frame: NSRect(x: 0, y: frame.height - Constants.Popup.headerHeight, width: frame.width, height: Constants.Popup.headerHeight))
let mainView: NSView = NSView(frame: NSRect(x: Constants.Popup.margins, y: Constants.Popup.margins, width: frame.width - (Constants.Popup.margins*2), height: 0))
@@ -143,6 +146,13 @@ internal class PopupView: NSView {
self.mainView?.subviews.first{ !($0 is HeaderView) }?.display()
}
internal func disappear() {}
@objc private func listenChangingPopupSize(_ notification: Notification) {
if let moduleName = notification.userInfo?["module"] as? String, moduleName == self.title {
self.updateLayer()
}
}
}
internal class HeaderView: NSView {

View File

@@ -25,6 +25,8 @@ struct diskInfo {
var mediaBSDName: String = ""
var root: Bool = false
var removable: Bool = false
}
struct DiskList: value_t {
@@ -78,6 +80,7 @@ public class Disk: Module {
guard self.available else { return }
self.capacityReader = CapacityReader()
self.capacityReader?.store = store
self.selectedDisk = store!.pointee.string(key: "\(self.config.name)_disk", defaultValue: self.selectedDisk)
self.capacityReader?.readyCallback = { [unowned self] in
@@ -91,6 +94,9 @@ public class Disk: Module {
self.selectedDisk = value
self.capacityReader?.read()
}
self.settingsView.callback = { [unowned self] in
self.capacityReader?.read()
}
if let reader = self.capacityReader {
self.addReader(reader)

View File

@@ -26,6 +26,11 @@ internal class Popup: NSView {
}
internal func usageCallback(_ value: DiskList) {
if self.list.count != value.list.count {
self.subviews.forEach{ $0.removeFromSuperview() }
self.list = [:]
}
value.list.reversed().forEach { (d: diskInfo) in
if self.list[d.name] == nil {
DispatchQueue.main.async(execute: {
@@ -37,13 +42,19 @@ internal class Popup: NSView {
path: d.path
)
self.addSubview(self.list[d.name]!)
self.setFrameSize(NSSize(width: self.frame.width, height: ((self.diskFullHeight + Constants.Popup.margins) * CGFloat(self.list.count)) - Constants.Popup.margins))
})
} else {
self.list[d.name]?.update(free: d.freeSize)
}
}
DispatchQueue.main.async(execute: {
let h: CGFloat = ((self.diskFullHeight + Constants.Popup.margins) * CGFloat(self.list.count)) - Constants.Popup.margins
if self.frame.size.height != h {
self.setFrameSize(NSSize(width: self.frame.width, height: h))
NotificationCenter.default.post(name: .updatePopupSize, object: nil, userInfo: ["module": "Disk"])
}
})
}
}

View File

@@ -11,9 +11,11 @@
import Cocoa
import ModuleKit
import StatsKit
internal class CapacityReader: Reader<DiskList> {
private var disks: DiskList = DiskList()
public var store: UnsafePointer<Store>? = nil
public override func setup() {
self.interval = 10000
@@ -21,7 +23,9 @@ internal class CapacityReader: Reader<DiskList> {
public override func read() {
let keys: [URLResourceKey] = [.volumeNameKey]
let removableState = store?.pointee.bool(key: "Disk_removable", defaultValue: false) ?? false
let paths = FileManager.default.mountedVolumeURLs(includingResourceValuesForKeys: keys)!
if let session = DASessionCreate(kCFAllocatorDefault) {
for url in paths {
if url.pathComponents.count == 1 || (url.pathComponents.count > 1 && url.pathComponents[1] == "Volumes") {
@@ -29,8 +33,13 @@ internal class CapacityReader: Reader<DiskList> {
if let diskName = DADiskGetBSDName(disk) {
let BSDName: String = String(cString: diskName)
if let _: diskInfo = self.disks.getDiskByBSDName(BSDName) {
if let d: diskInfo = self.disks.getDiskByBSDName(BSDName) {
if let idx = self.disks.list.firstIndex(where: { $0.mediaBSDName == BSDName }) {
if d.removable && !removableState {
self.disks.list.remove(at: idx)
continue
}
if let path = self.disks.list[idx].path {
self.disks.list[idx].freeSize = freeDiskSpaceInBytes(path.absoluteString)
}
@@ -38,8 +47,9 @@ internal class CapacityReader: Reader<DiskList> {
continue
}
if let d = getDisk(disk) {
if let d = getDisk(disk, removableState: removableState) {
self.disks.list.append(d)
self.disks.list.sort{ $1.removable }
}
}
}
@@ -50,7 +60,7 @@ internal class CapacityReader: Reader<DiskList> {
self.callback(self.disks)
}
private func getDisk(_ disk: DADisk) -> diskInfo? {
private func getDisk(_ disk: DADisk, removableState: Bool) -> diskInfo? {
var d: diskInfo = diskInfo()
if let bsdName = DADiskGetBSDName(disk) {
@@ -61,7 +71,10 @@ internal class CapacityReader: Reader<DiskList> {
if let dict = diskDescription as? [String: AnyObject] {
if let removable = dict[kDADiskDescriptionMediaRemovableKey as String] {
if removable as! Bool {
return nil
if !removableState {
return nil
}
d.removable = true
}
}

View File

@@ -22,10 +22,13 @@ internal class Settings: NSView, Settings_v {
private var selectedDisk: String
private var button: NSPopUpButton?
private var removableState: Bool = false
public init(_ title: String, store: UnsafePointer<Store>) {
self.title = title
self.store = store
self.selectedDisk = store.pointee.string(key: "\(self.title)_disk", defaultValue: "")
self.removableState = store.pointee.bool(key: "\(self.title)_removable", defaultValue: self.removableState)
super.init(frame: CGRect(x: Constants.Settings.margin, y: Constants.Settings.margin, width: Constants.Settings.width - (Constants.Settings.margin*2), height: 0))
self.wantsLayer = true
self.canDrawConcurrently = true
@@ -38,13 +41,21 @@ internal class Settings: NSView, Settings_v {
public func load(widget: widget_t) {
self.subviews.forEach{ $0.removeFromSuperview() }
let rowHeight: CGFloat = 30
self.addDiskSelector()
self.setFrameSize(NSSize(width: self.frame.width, height: 30 + (Constants.Settings.margin*2)))
self.addSubview(ToggleTitleRow(
frame: NSRect(x: Constants.Settings.margin, y: Constants.Settings.margin + (rowHeight + Constants.Settings.margin) * 0, width: self.frame.width - (Constants.Settings.margin*2), height: rowHeight),
title: "Show removable disks",
action: #selector(toggleRemovable),
state: self.removableState
))
self.setFrameSize(NSSize(width: self.frame.width, height: rowHeight*2 + (Constants.Settings.margin*3)))
}
private func addDiskSelector() {
let view: NSView = NSView(frame: NSRect(x: Constants.Settings.margin, y: Constants.Settings.margin, width: self.frame.width, height: 29))
let view: NSView = NSView(frame: NSRect(x: Constants.Settings.margin, y: Constants.Settings.margin*2 + 30, width: self.frame.width, height: 29))
let rowTitle: NSTextField = LabelField(frame: NSRect(x: 0, y: (view.frame.height - 16)/2, width: view.frame.width - 52, height: 17), "Disk to show")
rowTitle.font = NSFont.systemFont(ofSize: 13, weight: .light)
@@ -63,6 +74,10 @@ internal class Settings: NSView, Settings_v {
internal func setList(_ list: DiskList) {
let disks = list.list.map{ $0.name }
DispatchQueue.main.async(execute: {
if self.button?.itemTitles.count != disks.count {
self.button?.removeAllItems()
}
if disks != self.button?.itemTitles {
self.button?.addItems(withTitles: disks)
if self.selectedDisk != "" {
@@ -72,10 +87,23 @@ internal class Settings: NSView, Settings_v {
})
}
@objc func handleSelection(_ sender: NSPopUpButton) {
@objc private func handleSelection(_ sender: NSPopUpButton) {
guard let item = sender.selectedItem else { return }
self.selectedDisk = item.title
self.store.pointee.set(key: "\(self.title)_disk", value: item.title)
self.selectedDiskHandler(item.title)
}
@objc private func toggleRemovable(_ 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.removableState = state! == .on ? true : false
self.store.pointee.set(key: "\(self.title)_removable", value: self.removableState)
self.callback()
}
}

View File

@@ -375,6 +375,7 @@ public extension Notification.Name {
static let switchWidget = Notification.Name("switchWidget")
static let checkForUpdates = Notification.Name("checkForUpdates")
static let clickInSettings = Notification.Name("clickInSettings")
static let updatePopupSize = Notification.Name("updatePopupSize")
}
public class NSButtonWithPadding: NSButton {