2018-08-04 21:49:32 +08:00
|
|
|
//
|
2018-11-30 22:14:20 +08:00
|
|
|
// MenuItemFactory.swift
|
2018-08-04 21:49:32 +08:00
|
|
|
// ClashX
|
|
|
|
//
|
|
|
|
// Created by CYC on 2018/8/4.
|
2018-08-08 13:47:38 +08:00
|
|
|
// Copyright © 2018年 yichengchen. All rights reserved.
|
2018-08-04 21:49:32 +08:00
|
|
|
//
|
|
|
|
|
|
|
|
import Cocoa
|
|
|
|
import SwiftyJSON
|
|
|
|
import RxCocoa
|
|
|
|
|
2018-11-30 22:14:20 +08:00
|
|
|
class MenuItemFactory {
|
2019-10-09 20:33:57 +08:00
|
|
|
static func menuItems(completionHandler: @escaping (([NSMenuItem])->Void)){
|
2019-10-06 12:22:21 +08:00
|
|
|
|
|
|
|
if ConfigManager.shared.currentConfig?.mode == .direct {
|
2019-10-09 20:33:57 +08:00
|
|
|
completionHandler([])
|
|
|
|
return
|
2019-10-06 12:22:21 +08:00
|
|
|
}
|
|
|
|
|
2019-10-09 20:33:57 +08:00
|
|
|
ApiRequest.requestProxyGroupList() {
|
|
|
|
proxyInfo in
|
|
|
|
var menuItems = [NSMenuItem]()
|
2019-03-23 19:13:28 +08:00
|
|
|
|
2019-10-09 20:33:57 +08:00
|
|
|
for proxy in proxyInfo.proxyGroups {
|
|
|
|
var menu:NSMenuItem?
|
|
|
|
switch proxy.type {
|
|
|
|
case .select: menu = self.generateSelectorMenuItem(proxyGroup: proxy, proxyInfo: proxyInfo)
|
|
|
|
case .urltest,.fallback: menu = generateUrlTestFallBackMenuItem(proxyGroup: proxy, proxyInfo: proxyInfo)
|
|
|
|
case .loadBalance:
|
|
|
|
menu = generateLoadBalanceMenuItem(proxyGroup: proxy, proxyInfo: proxyInfo)
|
|
|
|
default: continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if let menu = menu {
|
|
|
|
menuItems.append(menu)
|
|
|
|
menu.isEnabled=true
|
|
|
|
}
|
2018-08-04 21:49:32 +08:00
|
|
|
}
|
2019-10-09 20:33:57 +08:00
|
|
|
completionHandler(menuItems.reversed())
|
2018-08-04 21:49:32 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-10 21:42:43 +08:00
|
|
|
|
2019-03-17 23:32:37 +08:00
|
|
|
static func generateSelectorMenuItem(proxyGroup:ClashProxy,
|
2019-03-23 19:13:28 +08:00
|
|
|
proxyInfo:ClashProxyResp) -> NSMenuItem? {
|
|
|
|
let proxyMap = proxyInfo.proxiesMap
|
|
|
|
|
2018-08-11 12:18:57 +08:00
|
|
|
let isGlobalMode = ConfigManager.shared.currentConfig?.mode == .global
|
2019-05-10 21:42:43 +08:00
|
|
|
if isGlobalMode {
|
2019-03-17 22:00:47 +08:00
|
|
|
if proxyGroup.name != "GLOBAL" {return nil}
|
2018-08-05 19:45:37 +08:00
|
|
|
} else {
|
2019-03-17 22:00:47 +08:00
|
|
|
if proxyGroup.name == "GLOBAL" {return nil}
|
2018-08-05 19:45:37 +08:00
|
|
|
}
|
|
|
|
|
2019-03-17 22:00:47 +08:00
|
|
|
let menu = NSMenuItem(title: proxyGroup.name, action: nil, keyEquivalent: "")
|
|
|
|
let selectedName = proxyGroup.now ?? ""
|
2019-10-16 22:46:03 +08:00
|
|
|
if !ConfigManager.shared.disableShowCurrentProxyInMenu {
|
|
|
|
menu.view = ProxyGroupMenuItemView(group: proxyGroup.name, targetProxy: selectedName)
|
|
|
|
}
|
2019-03-17 22:00:47 +08:00
|
|
|
let submenu = NSMenu(title: proxyGroup.name)
|
2018-08-11 14:02:34 +08:00
|
|
|
var hasSelected = false
|
2019-03-17 23:32:37 +08:00
|
|
|
|
2019-03-17 22:00:47 +08:00
|
|
|
for proxy in proxyGroup.all ?? []{
|
2019-03-17 23:32:37 +08:00
|
|
|
guard let proxyModel = proxyMap[proxy] else {continue}
|
|
|
|
|
|
|
|
if isGlobalMode && proxyModel.type == .select {
|
2019-03-17 22:00:47 +08:00
|
|
|
continue
|
2018-08-11 12:18:57 +08:00
|
|
|
}
|
2019-03-17 23:32:37 +08:00
|
|
|
let proxyItem = ProxyMenuItem(proxy: proxyModel, action: #selector(MenuItemFactory.actionSelectProxy(sender:)),
|
|
|
|
maxProxyNameLength:proxyGroup.maxProxyNameLength)
|
2018-11-30 22:14:20 +08:00
|
|
|
proxyItem.target = MenuItemFactory.self
|
2019-03-17 22:00:47 +08:00
|
|
|
proxyItem.isSelected = proxy == selectedName
|
2018-12-09 00:46:36 +08:00
|
|
|
|
2019-02-18 21:38:34 +08:00
|
|
|
if proxyItem.isSelected {hasSelected = true}
|
2018-08-05 19:45:37 +08:00
|
|
|
submenu.addItem(proxyItem)
|
2018-11-04 17:20:25 +08:00
|
|
|
}
|
2019-03-17 23:32:37 +08:00
|
|
|
|
2018-08-11 14:02:34 +08:00
|
|
|
if (!hasSelected && submenu.items.count>0) {
|
2018-12-09 00:46:36 +08:00
|
|
|
self.actionSelectProxy(sender: submenu.items[0] as! ProxyMenuItem)
|
2018-08-11 14:02:34 +08:00
|
|
|
}
|
2019-10-16 22:46:03 +08:00
|
|
|
addSpeedTestMenuItem(submenu, proxyGroup: proxyGroup)
|
|
|
|
menu.submenu = submenu
|
|
|
|
if !ConfigManager.shared.disableShowCurrentProxyInMenu {
|
|
|
|
menu.view = ProxyGroupMenuItemView(group: proxyGroup.name, targetProxy: selectedName)
|
|
|
|
}
|
2018-08-05 19:45:37 +08:00
|
|
|
return menu
|
|
|
|
}
|
|
|
|
|
2019-05-10 21:42:43 +08:00
|
|
|
|
|
|
|
static func generateUrlTestFallBackMenuItem(proxyGroup:ClashProxy,proxyInfo:ClashProxyResp)->NSMenuItem? {
|
2019-03-23 19:13:28 +08:00
|
|
|
|
|
|
|
let proxyMap = proxyInfo.proxiesMap
|
2019-03-17 22:00:47 +08:00
|
|
|
let selectedName = proxyGroup.now ?? ""
|
2019-05-10 21:42:43 +08:00
|
|
|
let menu = NSMenuItem(title: proxyGroup.name, action: nil, keyEquivalent: "")
|
2019-10-16 22:46:03 +08:00
|
|
|
if !ConfigManager.shared.disableShowCurrentProxyInMenu {
|
|
|
|
menu.view = ProxyGroupMenuItemView(group: proxyGroup.name, targetProxy: selectedName)
|
|
|
|
}
|
2019-03-17 22:00:47 +08:00
|
|
|
let submenu = NSMenu(title: proxyGroup.name)
|
2018-08-05 19:45:37 +08:00
|
|
|
|
2019-03-23 19:13:28 +08:00
|
|
|
let nowMenuItem = NSMenuItem(title: "now:\(selectedName)", action: #selector(empty), keyEquivalent: "")
|
|
|
|
nowMenuItem.target = MenuItemFactory.self
|
2019-05-10 21:42:43 +08:00
|
|
|
|
|
|
|
if let nowProxy = proxyMap[selectedName],let historyMenu = generateHistoryMenu(nowProxy) {
|
|
|
|
nowMenuItem.submenu = historyMenu
|
|
|
|
}
|
2019-03-23 19:13:28 +08:00
|
|
|
|
2018-08-05 19:45:37 +08:00
|
|
|
submenu.addItem(nowMenuItem)
|
2019-03-23 19:13:28 +08:00
|
|
|
submenu.addItem(NSMenuItem.separator())
|
|
|
|
|
|
|
|
for proxyName in proxyGroup.all ?? [] {
|
|
|
|
guard let proxy = proxyMap[proxyName] else {continue}
|
2019-05-10 21:42:43 +08:00
|
|
|
let proxyMenuItem = NSMenuItem(title: proxy.name, action: #selector(empty), keyEquivalent: "")
|
|
|
|
proxyMenuItem.target = MenuItemFactory.self
|
2019-03-23 19:13:28 +08:00
|
|
|
if proxy.name == selectedName {
|
|
|
|
proxyMenuItem.state = .on
|
|
|
|
}
|
2019-05-10 21:42:43 +08:00
|
|
|
|
|
|
|
if let historyMenu = generateHistoryMenu(proxy){
|
2019-03-23 19:13:28 +08:00
|
|
|
proxyMenuItem.submenu = historyMenu
|
|
|
|
}
|
2019-05-10 21:42:43 +08:00
|
|
|
|
|
|
|
submenu.addItem(proxyMenuItem)
|
2019-03-23 19:13:28 +08:00
|
|
|
}
|
2018-08-05 19:45:37 +08:00
|
|
|
menu.submenu = submenu
|
|
|
|
return menu
|
|
|
|
}
|
|
|
|
|
2019-10-16 22:46:03 +08:00
|
|
|
static func addSpeedTestMenuItem(_ menus: NSMenu, proxyGroup: ClashProxy) {
|
|
|
|
menus.addItem(NSMenuItem.separator())
|
|
|
|
let speedTestItem = ProxyGroupSpeedTestMenuItem(group: proxyGroup, selector: #selector(actionSpeedTestGroup(sender:)))
|
|
|
|
speedTestItem.target = MenuItemFactory.self
|
|
|
|
menus.addItem(speedTestItem)
|
|
|
|
}
|
|
|
|
|
2019-05-10 21:42:43 +08:00
|
|
|
static func generateHistoryMenu(_ proxy:ClashProxy) -> NSMenu? {
|
|
|
|
let historyMenu = NSMenu(title: "")
|
|
|
|
for his in proxy.history {
|
|
|
|
historyMenu.addItem(
|
|
|
|
NSMenuItem(title: "\(his.dateDisplay) \(his.delayDisplay)", action: nil, keyEquivalent: ""))
|
|
|
|
}
|
|
|
|
return historyMenu.items.count > 0 ? historyMenu : nil
|
|
|
|
}
|
|
|
|
|
2019-03-23 19:13:28 +08:00
|
|
|
static func generateLoadBalanceMenuItem(proxyGroup:ClashProxy, proxyInfo:ClashProxyResp)->NSMenuItem? {
|
|
|
|
|
|
|
|
let proxyMap = proxyInfo.proxiesMap
|
|
|
|
|
2019-03-17 22:00:47 +08:00
|
|
|
let menu = NSMenuItem(title: proxyGroup.name, action: nil, keyEquivalent: "")
|
|
|
|
let submenu = NSMenu(title: proxyGroup.name)
|
2019-02-15 22:47:17 +08:00
|
|
|
|
2019-03-17 22:00:47 +08:00
|
|
|
for proxy in proxyGroup.all ?? [] {
|
2019-03-17 23:32:37 +08:00
|
|
|
guard let proxyModel = proxyMap[proxy] else {continue}
|
|
|
|
let proxyItem = ProxyMenuItem(proxy: proxyModel,
|
2019-03-23 19:13:28 +08:00
|
|
|
action:#selector(empty),
|
2019-03-17 23:32:37 +08:00
|
|
|
maxProxyNameLength:proxyGroup.maxProxyNameLength)
|
2019-02-18 21:40:56 +08:00
|
|
|
proxyItem.isSelected = false
|
2019-03-23 19:13:28 +08:00
|
|
|
proxyItem.target = MenuItemFactory.self
|
2019-02-15 22:47:17 +08:00
|
|
|
submenu.addItem(proxyItem)
|
|
|
|
}
|
|
|
|
|
|
|
|
menu.submenu = submenu
|
|
|
|
|
|
|
|
return menu
|
|
|
|
}
|
2018-11-30 22:14:20 +08:00
|
|
|
|
2018-12-01 22:57:39 +08:00
|
|
|
static func generateSwitchConfigSubMenu() -> NSMenu {
|
|
|
|
let subMenu = NSMenu(title: "Switch Configs")
|
2018-11-30 22:14:20 +08:00
|
|
|
for config in ConfigManager.getConfigFilesList() {
|
|
|
|
let item = NSMenuItem(title: config, action: #selector(MenuItemFactory.actionSelectConfig(sender:)), keyEquivalent: "")
|
|
|
|
item.target = MenuItemFactory.self
|
|
|
|
item.state = ConfigManager.selectConfigName == config ? .on : .off
|
2018-12-01 22:57:39 +08:00
|
|
|
subMenu.addItem(item)
|
2018-11-30 22:14:20 +08:00
|
|
|
}
|
2018-12-01 22:57:39 +08:00
|
|
|
return subMenu
|
2018-11-30 22:14:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
extension MenuItemFactory {
|
2018-12-09 00:46:36 +08:00
|
|
|
@objc static func actionSelectProxy(sender:ProxyMenuItem){
|
2018-08-04 21:49:32 +08:00
|
|
|
guard let proxyGroup = sender.menu?.title else {return}
|
2018-12-09 00:46:36 +08:00
|
|
|
let proxyName = sender.proxyName
|
2018-08-04 21:49:32 +08:00
|
|
|
|
|
|
|
ApiRequest.updateProxyGroup(group: proxyGroup, selectProxy: proxyName) { (success) in
|
|
|
|
if (success) {
|
|
|
|
for items in sender.menu?.items ?? [NSMenuItem]() {
|
|
|
|
items.state = .off
|
|
|
|
}
|
|
|
|
sender.state = .on
|
2018-08-06 23:06:50 +08:00
|
|
|
// remember select proxy
|
|
|
|
ConfigManager.selectedProxyMap[proxyGroup] = proxyName
|
2018-08-04 21:49:32 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-11-30 22:14:20 +08:00
|
|
|
@objc static func actionSelectConfig(sender:NSMenuItem){
|
|
|
|
let config = sender.title
|
|
|
|
ConfigManager.selectConfigName = config
|
2019-08-18 13:23:28 +08:00
|
|
|
NotificationCenter.default.post(name: kShouldUpDateConfig,
|
|
|
|
object: nil,
|
|
|
|
userInfo: ["notification": false])
|
2018-11-30 22:14:20 +08:00
|
|
|
}
|
2019-03-23 19:13:28 +08:00
|
|
|
|
2019-10-16 22:46:03 +08:00
|
|
|
@objc static func actionSpeedTestGroup(sender: ProxyGroupSpeedTestMenuItem) {
|
|
|
|
let testGroup = DispatchGroup()
|
|
|
|
|
|
|
|
for proxyName in sender.proxyGroup.all ?? [] {
|
|
|
|
testGroup.enter()
|
|
|
|
ApiRequest.getProxyDelay(proxyName: proxyName) { delay in
|
|
|
|
testGroup.leave()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
testGroup.notify(queue: DispatchQueue.main, execute: {
|
|
|
|
NSUserNotificationCenter.default.postSpeedTestFinishNotice()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-03-23 19:13:28 +08:00
|
|
|
@objc static func empty(){}
|
2018-08-04 21:49:32 +08:00
|
|
|
}
|
2018-10-02 12:05:55 +08:00
|
|
|
|