152 lines
3.6 KiB
Swift
152 lines
3.6 KiB
Swift
//
|
|
// TrayIconController.swift
|
|
// PrivadoVPN
|
|
//
|
|
// Created by Juraldinio on 12/7/20.
|
|
// Copyright © 2020 Privado LLC. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import AppKit
|
|
|
|
protocol TrayIconMenuItem {
|
|
var title: String { get }
|
|
var enabled: Bool { get }
|
|
var keyEquivalent: String? { get }
|
|
}
|
|
|
|
protocol TrayIconControllerInput: AnyObject {
|
|
func icon(named: String)
|
|
func icon(by url: URL)
|
|
func refresh()
|
|
func menu(enabled: Bool)
|
|
}
|
|
|
|
protocol TrayIconControllerOutput: AnyObject {
|
|
func showRequired()
|
|
func hideRequired()
|
|
func actionRequired()
|
|
//
|
|
func menuItemsCount() -> Int
|
|
func menuItem(at index: Int) -> TrayIconMenuItem?
|
|
func menuItem(selected row: Int)
|
|
}
|
|
|
|
final class TrayIconController: NSObject, TrayIconControllerModule, TrayIconControllerInput {
|
|
|
|
private let output: TrayIconControllerOutput
|
|
private let statusItem: NSStatusItem
|
|
private let menu = NSMenu()
|
|
|
|
init(output: TrayIconControllerOutput) {
|
|
self.output = output
|
|
self.statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
|
|
|
|
super.init()
|
|
|
|
self.menu.delegate = self
|
|
}
|
|
|
|
// MARK: - Private
|
|
|
|
@objc
|
|
private func menuItemHandler(_ sender: Any?) {
|
|
guard let menuItem = sender as? NSMenuItem else { return }
|
|
self.output.menuItem(selected: menuItem.tag)
|
|
}
|
|
|
|
@objc
|
|
private func onAction() {
|
|
self.output.actionRequired()
|
|
}
|
|
|
|
// MARK: - TrayIconControllerModule
|
|
|
|
var button: NSButton? { self.statusItem.button }
|
|
|
|
func show() {
|
|
self.output.showRequired()
|
|
}
|
|
|
|
func hide() {
|
|
self.output.hideRequired()
|
|
}
|
|
|
|
// MARK: - TrayIconControllerInput
|
|
|
|
func icon(named: String) {
|
|
let image = NSImage(named: NSImage.Name(named))
|
|
guard let button = self.statusItem.button else { return }
|
|
button.image = image
|
|
}
|
|
|
|
func icon(by url: URL) {
|
|
let image = NSImage(byReferencing: url)
|
|
guard let button = self.statusItem.button else { return }
|
|
button.image = image
|
|
}
|
|
|
|
func refresh() {
|
|
self.statusItem.menu?.update()
|
|
}
|
|
|
|
func menu(enabled: Bool) {
|
|
|
|
if enabled {
|
|
self.statusItem.menu = self.menu
|
|
|
|
if let button = self.statusItem.button {
|
|
button.target = nil
|
|
button.action = nil
|
|
}
|
|
|
|
} else {
|
|
|
|
self.statusItem.menu = nil
|
|
|
|
if let button = self.statusItem.button {
|
|
button.target = self
|
|
button.action = #selector(self.onAction)
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
extension TrayIconController: NSMenuDelegate {
|
|
|
|
func numberOfItems(in menu: NSMenu) -> Int {
|
|
return self.output.menuItemsCount()
|
|
}
|
|
|
|
func menu(_ menu: NSMenu, update item: NSMenuItem, at index: Int, shouldCancel: Bool) -> Bool {
|
|
|
|
guard let menuItem = self.output.menuItem(at: index) else {
|
|
return false
|
|
}
|
|
|
|
guard menuItem.title != "-" else {
|
|
menu.removeItem(item)
|
|
menu.insertItem(NSMenuItem.separator(), at: index)
|
|
return true
|
|
}
|
|
|
|
if let key = menuItem.keyEquivalent {
|
|
item.keyEquivalent = key
|
|
}
|
|
|
|
item.title = menuItem.title
|
|
item.tag = index
|
|
if menuItem.enabled {
|
|
item.action = #selector(self.menuItemHandler)
|
|
item.target = self
|
|
} else {
|
|
item.action = nil
|
|
item.target = nil
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
}
|