Merge branch 'meta-dev' into meta
This commit is contained in:
commit
727c4e7bb3
|
@ -7,6 +7,7 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
0106179F2AF38EFA005C7877 /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49FEC6682AD9369C00BAD9F5 /* Command.swift */; };
|
||||
015B976A2A4F2F4500F9FA4D /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 015B97692A4F2F4500F9FA4D /* Alamofire */; };
|
||||
015B976D2A4F2F6C00F9FA4D /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 015B976C2A4F2F6C00F9FA4D /* RxCocoa */; };
|
||||
015B976F2A4F2F6C00F9FA4D /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 015B976E2A4F2F6C00F9FA4D /* RxSwift */; };
|
||||
|
@ -221,6 +222,7 @@
|
|||
49D223392A1DA5F10002FFCB /* SSIDSuspendTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D223382A1DA5F10002FFCB /* SSIDSuspendTool.swift */; };
|
||||
49D6A45229AEEC15006487EF /* StatusItemTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D6A45129AEEC15006487EF /* StatusItemTool.swift */; };
|
||||
49D6A45629AEEC55006487EF /* StatusItemViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D6A45529AEEC55006487EF /* StatusItemViewProtocol.swift */; };
|
||||
49FEC6692AD9369C00BAD9F5 /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49FEC6682AD9369C00BAD9F5 /* Command.swift */; };
|
||||
8A2BBEA727A03ACB0081EBEF /* ProxySetting.sdef in Resources */ = {isa = PBXBuildFile; fileRef = 8A2BBEA627A03ACB0081EBEF /* ProxySetting.sdef */; };
|
||||
8ACD21BB27A04C7800BC4632 /* ProxySettingCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8ACD21BA27A04C7800BC4632 /* ProxySettingCommand.swift */; };
|
||||
8ACD21BD27A04ED500BC4632 /* ProxyModeChangeCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8ACD21BC27A04ED500BC4632 /* ProxyModeChangeCommand.swift */; };
|
||||
|
@ -399,6 +401,7 @@
|
|||
49D6A45529AEEC55006487EF /* StatusItemViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusItemViewProtocol.swift; sourceTree = "<group>"; };
|
||||
49D8276627E9B01700159D93 /* LoginKitWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LoginKitWrapper.h; sourceTree = "<group>"; };
|
||||
49D8276727E9B01700159D93 /* LoginKitWrapper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LoginKitWrapper.m; sourceTree = "<group>"; };
|
||||
49FEC6682AD9369C00BAD9F5 /* Command.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Command.swift; sourceTree = "<group>"; };
|
||||
8A2BBEA627A03ACB0081EBEF /* ProxySetting.sdef */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = ProxySetting.sdef; sourceTree = "<group>"; };
|
||||
8ACD21BA27A04C7800BC4632 /* ProxySettingCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxySettingCommand.swift; sourceTree = "<group>"; };
|
||||
8ACD21BC27A04ED500BC4632 /* ProxyModeChangeCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyModeChangeCommand.swift; sourceTree = "<group>"; };
|
||||
|
@ -515,6 +518,7 @@
|
|||
49D176A62355FE680093DD7B /* NetworkChangeNotifier.swift */,
|
||||
49B445152457CDF000B27E3E /* ClashStatusTool.swift */,
|
||||
49D223382A1DA5F10002FFCB /* SSIDSuspendTool.swift */,
|
||||
49FEC6682AD9369C00BAD9F5 /* Command.swift */,
|
||||
);
|
||||
path = Utils;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1019,6 +1023,7 @@
|
|||
01F335E82AD10D0B0048AF77 /* AlphaMetaDownloader.swift in Sources */,
|
||||
01F335E92AD10D0B0048AF77 /* NetworkChangeNotifier.swift in Sources */,
|
||||
01F335EA2AD10D0B0048AF77 /* GlobalShortCutViewController.swift in Sources */,
|
||||
0106179F2AF38EFA005C7877 /* Command.swift in Sources */,
|
||||
01F335EB2AD10D0B0048AF77 /* Notification.swift in Sources */,
|
||||
01F335EC2AD10D0B0048AF77 /* ClashMetaConfig.swift in Sources */,
|
||||
01F335ED2AD10D0B0048AF77 /* ProxyModeChangeCommand.swift in Sources */,
|
||||
|
@ -1135,6 +1140,7 @@
|
|||
49722FF0211F338B00650A41 /* EventStream.swift in Sources */,
|
||||
499A486522EEA3FD00F6C675 /* Array+Safe.swift in Sources */,
|
||||
F92D0B24236BC12000575E15 /* SavedProxyModel.swift in Sources */,
|
||||
49FEC6692AD9369C00BAD9F5 /* Command.swift in Sources */,
|
||||
F92D0B2A236C759100575E15 /* NSTextField+Vibrancy.swift in Sources */,
|
||||
49D223392A1DA5F10002FFCB /* SSIDSuspendTool.swift in Sources */,
|
||||
F910AA24240134AF00116E95 /* ProxyGroupMenu.swift in Sources */,
|
||||
|
|
|
@ -41,8 +41,8 @@ class Logger {
|
|||
}
|
||||
}
|
||||
|
||||
static func log(_ msg: String, level: ClashLogLevel = .info, function: String = #function) {
|
||||
shared.logToFile(msg: "[\(level.rawValue)] \(function) \(msg)", level: level)
|
||||
static func log(_ msg: String, level: ClashLogLevel = .info, file: String = #file, function: String = #function) {
|
||||
shared.logToFile(msg: "[\(level.rawValue)] \(file) \(function) \(msg)", level: level)
|
||||
}
|
||||
|
||||
func logFilePath() -> String {
|
||||
|
|
|
@ -71,6 +71,8 @@ class ClashWindowController<T: NSViewController>: NSWindowController, NSWindowDe
|
|||
}
|
||||
window?.makeKeyAndOrderFront(self)
|
||||
window?.delegate = self
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
window?.makeKeyAndOrderFront(nil)
|
||||
}
|
||||
|
||||
func windowWillClose(_ notification: Notification) {
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// Command.swift
|
||||
// ClashX
|
||||
//
|
||||
// Created by yicheng on 2023/10/13.
|
||||
// Copyright © 2023 west2online. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct Command {
|
||||
let cmd: String
|
||||
let args: [String]
|
||||
|
||||
func run() -> String {
|
||||
var output = ""
|
||||
|
||||
let task = Process()
|
||||
task.launchPath = cmd
|
||||
task.arguments = args
|
||||
|
||||
let outpipe = Pipe()
|
||||
task.standardOutput = outpipe
|
||||
|
||||
task.launch()
|
||||
|
||||
task.waitUntilExit()
|
||||
let outdata = outpipe.fileHandleForReading.readDataToEndOfFile()
|
||||
if var string = String(data: outdata, encoding: .utf8) {
|
||||
output = string.trimmingCharacters(in: .newlines)
|
||||
}
|
||||
return output
|
||||
}
|
||||
}
|
|
@ -198,8 +198,4 @@ class NetworkChangeNotifier {
|
|||
}
|
||||
return allowIPV6 ? ipv6 : nil
|
||||
}
|
||||
|
||||
static func getCurrentSSID() -> String? {
|
||||
return CWWiFiClient.shared().interface()?.ssid()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,24 +6,48 @@
|
|||
// Copyright © 2023 west2online. All rights reserved.
|
||||
//
|
||||
|
||||
import CoreLocation
|
||||
import CoreWLAN
|
||||
import Foundation
|
||||
import RxCocoa
|
||||
import RxSwift
|
||||
import AppKit
|
||||
|
||||
class SSIDSuspendTool {
|
||||
class SSIDSuspendTool: NSObject {
|
||||
static let shared = SSIDSuspendTool()
|
||||
var disposeBag = DisposeBag()
|
||||
func setup() {
|
||||
NotificationCenter
|
||||
.default
|
||||
.rx
|
||||
.notification(.systemNetworkStatusDidChange)
|
||||
.observe(on: MainScheduler.instance)
|
||||
.delay(.seconds(2), scheduler: MainScheduler.instance)
|
||||
.bind { [weak self] _ in
|
||||
self?.update()
|
||||
}.disposed(by: disposeBag)
|
||||
private var ssidChangePublisher = PublishSubject<String>()
|
||||
private var disposeBag = DisposeBag()
|
||||
private lazy var locationManager = CLLocationManager()
|
||||
|
||||
var showNoticeOnNotPermission = false
|
||||
|
||||
func setup() {
|
||||
if AppVersionUtil.hasVersionChanged {
|
||||
showNoticeOnNotPermission = true
|
||||
}
|
||||
requestPermissionIfNeed()
|
||||
do {
|
||||
try CWWiFiClient.shared().startMonitoringEvent(with: .ssidDidChange)
|
||||
CWWiFiClient.shared().delegate = self
|
||||
ssidChangePublisher
|
||||
.observe(on: MainScheduler.instance)
|
||||
.debounce(.seconds(1), scheduler: MainScheduler.instance)
|
||||
.delay(.seconds(1), scheduler: MainScheduler.instance)
|
||||
.bind { [weak self] _ in
|
||||
self?.update()
|
||||
}.disposed(by: disposeBag)
|
||||
} catch let err {
|
||||
Logger.log(String(describing: err), level: .warning)
|
||||
NotificationCenter
|
||||
.default
|
||||
.rx
|
||||
.notification(.systemNetworkStatusDidChange)
|
||||
.observe(on: MainScheduler.instance)
|
||||
.delay(.seconds(2), scheduler: MainScheduler.instance)
|
||||
.bind { [weak self] _ in
|
||||
self?.update()
|
||||
}.disposed(by: disposeBag)
|
||||
}
|
||||
ConfigManager.shared
|
||||
.proxyShouldPaused
|
||||
.asObservable()
|
||||
|
@ -40,6 +64,27 @@ class SSIDSuspendTool {
|
|||
update()
|
||||
}
|
||||
|
||||
func requestPermissionIfNeed() {
|
||||
defer {
|
||||
showNoticeOnNotPermission = false
|
||||
}
|
||||
if #available(macOS 14, *) {
|
||||
if Settings.disableSSIDList.isEmpty { return }
|
||||
if locationManager.authorizationStatus == .notDetermined {
|
||||
Logger.log("request location permission")
|
||||
locationManager.desiredAccuracy = kCLLocationAccuracyReduced
|
||||
locationManager.delegate = self
|
||||
locationManager.requestAlwaysAuthorization()
|
||||
} else if locationManager.authorizationStatus != .authorized {
|
||||
if showNoticeOnNotPermission {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||
self.openLocationSettings()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func update() {
|
||||
if shouldSuspend() {
|
||||
ConfigManager.shared.proxyShouldPaused.accept(true)
|
||||
|
@ -49,10 +94,52 @@ class SSIDSuspendTool {
|
|||
}
|
||||
|
||||
func shouldSuspend() -> Bool {
|
||||
if let currentSSID = NetworkChangeNotifier.getCurrentSSID() {
|
||||
if let currentSSID = getCurrentSSID() {
|
||||
return Settings.disableSSIDList.contains(currentSSID)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private func getCurrentSSID() -> String? {
|
||||
if #available(macOS 14, *) {
|
||||
if locationManager.authorizationStatus != .authorized {
|
||||
let info = Command(cmd: "/System/Library/PrivateFrameworks/Apple80211.framework/Resources/airport", args: ["-I"]).run()
|
||||
let ssid = info.components(separatedBy: "\n")
|
||||
.lazy
|
||||
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
|
||||
.first { $0.starts(with: "SSID:") }?
|
||||
.components(separatedBy: ":")
|
||||
.last?.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
return ssid
|
||||
}
|
||||
}
|
||||
return CWWiFiClient.shared().interface()?.ssid()
|
||||
}
|
||||
|
||||
private func openLocationSettings() {
|
||||
NSWorkspace.shared.open(URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Location")!)
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
NSAlert.alert(with: NSLocalizedString("Please enable the location service for ClashX to detect your current WiFi network's SSID name and provide the auto-suspend services.", comment: ""))
|
||||
}
|
||||
}
|
||||
|
||||
extension SSIDSuspendTool: CLLocationManagerDelegate {
|
||||
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
|
||||
Logger.log("Location status: \(status.rawValue)")
|
||||
if status != .authorized, showNoticeOnNotPermission {
|
||||
openLocationSettings()
|
||||
}
|
||||
showNoticeOnNotPermission = false
|
||||
}
|
||||
|
||||
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {}
|
||||
|
||||
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {}
|
||||
}
|
||||
|
||||
extension SSIDSuspendTool: CWEventDelegate {
|
||||
func ssidDidChangeForWiFiInterface(withName interfaceName: String) {
|
||||
ssidChangePublisher.onNext(interfaceName)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
||||
<string>ClashX use location info to detect your current WiFi network SSID name and provide the auto suspend services.</string>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>ClashX use location info to detect your current WiFi network SSID name and provide the auto suspend services.</string>
|
||||
<key>BETA</key>
|
||||
<true/>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
|
|
|
@ -125,12 +125,8 @@ class ClashProxy: Codable {
|
|||
var proxys = [SpeedtestAbleItem]()
|
||||
for proxy in allProxys {
|
||||
if let p = resp.proxiesMap[proxy] {
|
||||
if !ClashProxyType.isProxyGroup(p) {
|
||||
if let provider = p.enclosingProvider {
|
||||
proxys.append(.provider(name: p.name, provider: provider.name))
|
||||
} else {
|
||||
proxys.append(.proxy(name: p.name))
|
||||
}
|
||||
if let provider = p.enclosingProvider {
|
||||
proxys.append(.provider(name: p.name, provider: provider.name))
|
||||
} else {
|
||||
proxys.append(.group(name: p.name))
|
||||
}
|
||||
|
|
|
@ -200,6 +200,9 @@
|
|||
/* No comment provided by engineer. */
|
||||
"Open github release page to download " = "Open github release page to download ";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Please enable the location service for ClashX to detect your current WiFi network's SSID name and provide the auto-suspend services." = "Please enable the location service for ClashX to detect your current WiFi network's SSID name and provide the auto-suspend services.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Ports Open Fail, Please try to restart ClashX" = "Ports Open Fail, Please try to restart ClashX";
|
||||
|
||||
|
|
|
@ -205,6 +205,9 @@
|
|||
/* No comment provided by engineer. */
|
||||
"Open github release page to download " = "打开 GitHub Release 下载 ";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Please enable the location service for ClashX to detect your current WiFi network's SSID name and provide the auto-suspend services." = "请允许ClashX使用定位服务来获取当前所连接的WiFi名称从而提供按需暂停服务。";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Ports Open Fail, Please try to restart ClashX" = "端口打开失败,请尝试重启ClashX";
|
||||
|
||||
|
|
|
@ -172,6 +172,9 @@
|
|||
/* No comment provided by engineer. */
|
||||
"Open System Login Item Setting" = "打開系統登錄項設定";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Please enable the location service for ClashX to detect your current WiFi network's SSID name and provide the auto-suspend services." = "請允許 ClashX 使用定位服務,以獲取您目前連接的 WiFi 名稱,並提供按需暫停服務。";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Ports Open Fail, Please try to restart ClashX" = "端口打開失敗,請嘗試重啟ClashX";
|
||||
|
||||
|
|
|
@ -134,6 +134,9 @@ class GeneralSettingViewController: NSViewController {
|
|||
if url.isUrlVaild() || url.isEmpty {
|
||||
Settings.benchMarkUrl = url
|
||||
}
|
||||
SSIDSuspendTool.shared.showNoticeOnNotPermission = true
|
||||
SSIDSuspendTool.shared.requestPermissionIfNeed()
|
||||
SSIDSuspendTool.shared.update()
|
||||
}
|
||||
|
||||
@IBAction func actionResetIgnoreList(_ sender: Any) {
|
||||
|
|
Loading…
Reference in New Issue