2019-01-01 19:37:46 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
2021-06-17 14:56:46 +00:00
|
|
|
// Copyright © 2018-2021 WireGuard LLC. All Rights Reserved.
|
2019-01-01 19:37:46 +00:00
|
|
|
|
|
|
|
import Cocoa
|
|
|
|
|
2019-01-07 07:34:50 +00:00
|
|
|
class TunnelListRow: NSView {
|
2019-01-01 19:37:46 +00:00
|
|
|
var tunnel: TunnelContainer? {
|
|
|
|
didSet(value) {
|
|
|
|
// Bind to the tunnel's name
|
|
|
|
nameLabel.stringValue = tunnel?.name ?? ""
|
|
|
|
nameObservationToken = tunnel?.observe(\TunnelContainer.name) { [weak self] tunnel, _ in
|
|
|
|
self?.nameLabel.stringValue = tunnel.name
|
|
|
|
}
|
|
|
|
// Bind to the tunnel's status
|
2021-07-29 05:42:30 +00:00
|
|
|
statusImageView.image = TunnelListRow.image(for: tunnel)
|
2019-01-01 19:37:46 +00:00
|
|
|
statusObservationToken = tunnel?.observe(\TunnelContainer.status) { [weak self] tunnel, _ in
|
2021-07-29 05:42:30 +00:00
|
|
|
self?.statusImageView.image = TunnelListRow.image(for: tunnel)
|
|
|
|
}
|
|
|
|
isOnDemandEnabledObservationToken = tunnel?.observe(\TunnelContainer.isActivateOnDemandEnabled) { [weak self] tunnel, _ in
|
|
|
|
self?.statusImageView.image = TunnelListRow.image(for: tunnel)
|
2019-01-01 19:37:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let nameLabel: NSTextField = {
|
|
|
|
let nameLabel = NSTextField()
|
|
|
|
nameLabel.isEditable = false
|
|
|
|
nameLabel.isSelectable = false
|
|
|
|
nameLabel.isBordered = false
|
|
|
|
nameLabel.maximumNumberOfLines = 1
|
|
|
|
nameLabel.lineBreakMode = .byTruncatingTail
|
|
|
|
return nameLabel
|
|
|
|
}()
|
|
|
|
|
|
|
|
let statusImageView = NSImageView()
|
|
|
|
|
|
|
|
private var statusObservationToken: AnyObject?
|
|
|
|
private var nameObservationToken: AnyObject?
|
2021-07-29 05:42:30 +00:00
|
|
|
private var isOnDemandEnabledObservationToken: AnyObject?
|
2019-01-01 19:37:46 +00:00
|
|
|
|
|
|
|
init() {
|
|
|
|
super.init(frame: CGRect.zero)
|
|
|
|
|
|
|
|
addSubview(statusImageView)
|
|
|
|
addSubview(nameLabel)
|
|
|
|
statusImageView.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
nameLabel.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
nameLabel.backgroundColor = .clear
|
|
|
|
NSLayoutConstraint.activate([
|
|
|
|
self.leadingAnchor.constraint(equalTo: statusImageView.leadingAnchor),
|
|
|
|
statusImageView.trailingAnchor.constraint(equalTo: nameLabel.leadingAnchor),
|
|
|
|
statusImageView.widthAnchor.constraint(equalToConstant: 20),
|
|
|
|
nameLabel.trailingAnchor.constraint(equalTo: self.trailingAnchor),
|
|
|
|
statusImageView.centerYAnchor.constraint(equalTo: self.centerYAnchor),
|
|
|
|
nameLabel.centerYAnchor.constraint(equalTo: self.centerYAnchor)
|
|
|
|
])
|
|
|
|
}
|
|
|
|
|
|
|
|
required init?(coder decoder: NSCoder) {
|
|
|
|
fatalError("init(coder:) has not been implemented")
|
|
|
|
}
|
|
|
|
|
2021-07-29 05:42:30 +00:00
|
|
|
static func image(for tunnel: TunnelContainer?) -> NSImage? {
|
|
|
|
guard let tunnel = tunnel else { return nil }
|
|
|
|
switch tunnel.status {
|
2019-01-01 19:37:46 +00:00
|
|
|
case .active, .restarting, .reasserting:
|
|
|
|
return NSImage(named: NSImage.statusAvailableName)
|
2019-01-18 20:17:53 +00:00
|
|
|
case .activating, .waiting, .deactivating:
|
2019-01-01 19:37:46 +00:00
|
|
|
return NSImage(named: NSImage.statusPartiallyAvailableName)
|
2019-01-18 20:17:53 +00:00
|
|
|
case .inactive:
|
2021-07-29 05:42:30 +00:00
|
|
|
if tunnel.isActivateOnDemandEnabled {
|
|
|
|
return NSImage(named: NSImage.Name.statusOnDemandEnabled)
|
|
|
|
} else {
|
|
|
|
return NSImage(named: NSImage.statusNoneName)
|
|
|
|
}
|
2019-01-01 19:37:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override func prepareForReuse() {
|
|
|
|
nameLabel.stringValue = ""
|
|
|
|
statusImageView.image = nil
|
|
|
|
}
|
|
|
|
}
|
2021-07-29 05:42:30 +00:00
|
|
|
|
|
|
|
extension NSImage.Name {
|
|
|
|
static let statusOnDemandEnabled = NSImage.Name("StatusCircleYellow")
|
|
|
|
}
|