Skip to content

Commit

Permalink
UI: Fix WiFiMenuItemView appearance in Big Sur
Browse files Browse the repository at this point in the history
  • Loading branch information
williambj1 committed Nov 21, 2020
1 parent 36d2662 commit 434342a
Showing 1 changed file with 145 additions and 62 deletions.
207 changes: 145 additions & 62 deletions HeliPort/Appearance/WiFiMenuItemView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,119 +16,194 @@
import Foundation
import Cocoa

class WifiMenuItemView: NSVisualEffectView {
class WifiMenuItemView: NSView {

let statusImage: NSImageView = {
// MARK: Initializers

private var currentWindow: NSWindow?
private var heightConstraint: NSLayoutConstraint!

private let menuBarHeight: CGFloat = {
if #available(macOS 11, *) {
return 22
} else {
return 19
}
}()

private let effectView: NSVisualEffectView = {
let effectView = NSVisualEffectView()
effectView.material = .popover
effectView.state = .active
effectView.isEmphasized = true
effectView.blendingMode = .behindWindow
return effectView
}()

private let statusImage: NSImageView = {
let statusImage = NSImageView()
statusImage.image = NSImage(named: NSImage.menuOnStateTemplateName)
statusImage.isHidden = true
statusImage.setContentHuggingPriority(.defaultHigh, for: .horizontal)
return statusImage
}()
statusImage.isHidden = true

let ssidLabel: NSTextField = {
let ssidLabel = NSTextField(labelWithString: "")
ssidLabel.font = NSFont.systemFont(ofSize: 14)
return ssidLabel
if #available(OSX 11.0, *) {
statusImage.image = NSImage(named: NSImage.menuOnStateTemplateName)?
.withSymbolConfiguration(NSImage.SymbolConfiguration(pointSize: 13,
weight: .bold,
scale: .small))
} else {
statusImage.image = NSImage(named: NSImage.menuOnStateTemplateName)
}

return statusImage
}()

let lockImage: NSImageView = {
private let lockImage: NSImageView = {
let lockImage = NSImageView()
lockImage.image = NSImage(named: NSImage.lockLockedTemplateName)
lockImage.setContentHuggingPriority(.defaultHigh, for: .horizontal)

if #available(OSX 11.0, *) {
lockImage.image = NSImage(named: NSImage.lockLockedTemplateName)?
.withSymbolConfiguration(NSImage.SymbolConfiguration(pointSize: 14,
weight: .semibold,
scale: .medium))
} else {
lockImage.image = NSImage(named: NSImage.lockLockedTemplateName)
}

return lockImage
}()

let signalImage: NSImageView = {
private let signalImage: NSImageView = {
let signalImage = NSImageView()
signalImage.setContentHuggingPriority(.defaultHigh, for: .horizontal)
return signalImage
}()

var isMouseOver: Bool = false {
willSet(hover) {
material = hover ? .selection : .menu
isEmphasized = hover
ssidLabel.textColor = hover ? .white : .textColor
if #available(OSX 10.14, *) {
statusImage.contentTintColor = hover ? .white : .textColor
lockImage.contentTintColor = hover ? .white : .textColor
signalImage.contentTintColor = hover ? .white : .textColor
}
private let ssidLabel: NSTextField = {
let ssidLabel = NSTextField(labelWithString: "")

if #available(macOS 11, *) {
ssidLabel.font = NSFont.menuFont(ofSize: 0)
} else {
ssidLabel.font = NSFont.systemFont(ofSize: 14)
}

return ssidLabel
}()

public init(networkInfo: NetworkInfo) {
self.networkInfo = networkInfo
super.init(frame: NSRect(x: 0, y: 0, width: 0, height: menuBarHeight))

self.addSubview(effectView)
effectView.addSubview(statusImage)
effectView.addSubview(ssidLabel)
effectView.addSubview(lockImage)
effectView.addSubview(signalImage)

setupLayout()
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

// MARK: Public

public var networkInfo: NetworkInfo {
willSet(networkInfo) {
ssidLabel.stringValue = networkInfo.ssid
lockImage.isHidden = networkInfo.auth.security == ITL80211_SECURITY_NONE
signalImage.image = StatusBarIcon.getRssiImage(Int16(networkInfo.rssi))
layoutSubtreeIfNeeded()
}
}

var visible: Bool = true {
public var visible: Bool = true {
willSet(visible) {
isHidden = !visible
heightConstraint.constant = visible ? 19 : 0
heightConstraint.constant = visible ? menuBarHeight : 0
layoutSubtreeIfNeeded()
}
}

var connected: Bool = false {
public var connected: Bool = false {
willSet(connected) {
statusImage.isHidden = !connected
}
}

var currentWindow: NSWindow?

var networkInfo: NetworkInfo {
willSet(networkInfo) {
ssidLabel.stringValue = networkInfo.ssid
lockImage.isHidden = networkInfo.auth.security == ITL80211_SECURITY_NONE
signalImage.image = StatusBarIcon.getRssiImage(Int16(networkInfo.rssi))
layoutSubtreeIfNeeded()
public func checkHighlight() {
if visible, let position = currentWindow?.mouseLocationOutsideOfEventStream {
isMouseOver = bounds.contains(convert(position, from: nil))
}
}

var heightConstraint: NSLayoutConstraint!
// MARK: Private

private var isMouseOver: Bool = false {
willSet(hover) {
effectView.material = hover ? .selection : .popover
effectView.isEmphasized = hover

func setupLayout() {
subviews.forEach { $0.translatesAutoresizingMaskIntoConstraints = false }
ssidLabel.textColor = hover ? .selectedMenuItemTextColor : .controlTextColor

heightConstraint = heightAnchor.constraint(equalToConstant: 19)
statusImage.cell?.backgroundStyle = hover ? .emphasized : .normal
lockImage.cell?.backgroundStyle = hover ? .emphasized : .normal
signalImage.cell?.backgroundStyle = hover ? .emphasized : .normal
}
}

private func setupLayout() {

let effectPadding: CGFloat
let statusPadding: CGFloat
let statusWidth: CGFloat
let lockWidth: CGFloat
if #available(macOS 11, *) {
effectView.wantsLayer = true
effectView.layer?.cornerRadius = 4
effectView.layer?.masksToBounds = true
effectPadding = 5
statusPadding = 10
statusWidth = 15
lockWidth = 16
} else {
effectPadding = 0
statusPadding = 6
statusWidth = 12
lockWidth = 10
}

heightConstraint = heightAnchor.constraint(equalToConstant: menuBarHeight)
heightConstraint.priority = NSLayoutConstraint.Priority(rawValue: 1000)
heightConstraint.isActive = true

statusImage.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
statusImage.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 6).isActive = true
statusImage.widthAnchor.constraint(equalToConstant: 12).isActive = true
statusImage.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: statusPadding).isActive = true
statusImage.widthAnchor.constraint(equalToConstant: statusWidth).isActive = true

ssidLabel.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
ssidLabel.leadingAnchor.constraint(equalTo: statusImage.trailingAnchor, constant: 3).isActive = true
ssidLabel.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
ssidLabel.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true

lockImage.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
lockImage.leadingAnchor.constraint(equalTo: ssidLabel.trailingAnchor, constant: 10).isActive = true
lockImage.widthAnchor.constraint(equalToConstant: 10).isActive = true
lockImage.widthAnchor.constraint(equalToConstant: lockWidth).isActive = true

signalImage.centerYAnchor.constraint(equalTo: self.centerYAnchor, constant: 1).isActive = true
signalImage.leadingAnchor.constraint(equalTo: lockImage.trailingAnchor, constant: 12).isActive = true
signalImage.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -12).isActive = true
signalImage.widthAnchor.constraint(equalToConstant: 18).isActive = true
}

init(networkInfo: NetworkInfo) {
self.networkInfo = networkInfo
super.init(frame: NSRect.zero)

self.addSubview(statusImage)
self.addSubview(ssidLabel)
self.addSubview(lockImage)
self.addSubview(signalImage)
self.material = .menu

setupLayout()
effectView.translatesAutoresizingMaskIntoConstraints = false
effectView.subviews.forEach { $0.translatesAutoresizingMaskIntoConstraints = false }
effectView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: effectPadding).isActive = true
effectView.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -effectPadding).isActive = true
effectView.topAnchor.constraint(equalTo: topAnchor).isActive = true
effectView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}

func checkHighlight() {
if visible, let position = currentWindow?.mouseLocationOutsideOfEventStream {
isMouseOver = bounds.contains(convert(position, from: nil))
}
}
// MARK: Overrides

override func mouseUp(with event: NSEvent) {
isMouseOver = false // NSWindow pop up could escape mouseExit
Expand All @@ -150,7 +225,15 @@ class WifiMenuItemView: NSVisualEffectView {
checkHighlight()
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
override func layout() {
super.layout()
if #available(macOS 11, *) {
effectView.frame = CGRect(x: 5, // effectPadding
y: 0,
width: bounds.width - 10, // effectPadding * 2
height: bounds.height)
} else {
effectView.frame = bounds
}
}
}

0 comments on commit 434342a

Please sign in to comment.