Files

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
}
}