Merge branch 'meta-dev' into meta

This commit is contained in:
mrFq1 2023-06-07 10:05:35 +08:00
commit 5aaffa72c8
35 changed files with 2843 additions and 156 deletions

View File

@ -25,11 +25,11 @@ jobs:
uses: robinraju/release-downloader@v1.8
with:
repository: 'MetaCubeX/Clash.Meta'
# tag: "v1.14.4"
# fileName: ".*darwin.*64-v.*.gz"
tag: "v1.14.4"
fileName: ".*darwin.*64-v.*.gz"
releaseId: "62870807"
fileName: ".*darwin.*64-alpha.*.gz"
# releaseId: "62870807"
# fileName: ".*darwin.*64-alpha.*.gz"
out-file-path: "clash.meta"
token: ${{ secrets.GITHUB_TOKEN }}
@ -43,15 +43,23 @@ jobs:
- name: build
run: xcodebuild archive -workspace ClashX.xcworkspace -scheme ClashX -archivePath archive/ClashX.xcarchive -showBuildTimingSummary -allowProvisioningUpdates
- name: build-SwiftUI
run: |
xcodebuild -resolvePackageDependencies -project ClashX\ SwiftUI.xcodeproj
xcodebuild archive -project ClashX\ SwiftUI.xcodeproj -scheme ClashX\ Meta -archivePath archive/ClashX\ SwiftUI.xcarchive -showBuildTimingSummary -allowProvisioningUpdates
- name: create zip
run: ditto -c -k --sequesterRsrc --keepParent archive/ClashX.xcarchive/Products/Applications/ClashX\ Meta.app ClashX\ Meta.zip
run: |
ditto -c -k --sequesterRsrc --keepParent archive/ClashX.xcarchive/Products/Applications/ClashX\ Meta.app ClashX\ Meta.zip
ditto -c -k --sequesterRsrc --keepParent archive/ClashX\ SwiftUI.xcarchive/Products/Applications/ClashX\ Meta.app ClashX\ Meta\ SwiftUI(macOS 12.0+).zip
- name: upload Artifact
uses: actions/upload-artifact@v3
if: "!startsWith(github.ref, 'refs/tags/')"
with:
name: "ClashX Meta.zip"
path: "ClashX Meta.zip"
path: "*.zip"
- name: upload build to github
uses: softprops/action-gh-release@v1
@ -60,4 +68,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
generate_release_notes: true
files: "ClashX Meta.zip"
files: |
"ClashX Meta.zip"
"ClashX Meta SwiftUI(macOS 12.0+).zip"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,167 @@
{
"pins" : [
{
"identity" : "alamofire",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Alamofire/Alamofire",
"state" : {
"revision" : "78424be314842833c04bc3bef5b72e85fff99204",
"version" : "5.6.4"
}
},
{
"identity" : "clashx-dashboard",
"kind" : "remoteSourceControl",
"location" : "https://github.com/mrFq1/ClashX-Dashboard",
"state" : {
"branch" : "dev",
"revision" : "f488f41f8dbb6d2e718101c51380f605ec2a197c"
}
},
{
"identity" : "cocoalumberjack",
"kind" : "remoteSourceControl",
"location" : "https://github.com/CocoaLumberjack/CocoaLumberjack",
"state" : {
"revision" : "0188d31089b5881a269e01777be74c7316924346",
"version" : "3.8.0"
}
},
{
"identity" : "differencekit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/ra1028/DifferenceKit.git",
"state" : {
"revision" : "073b9671ce2b9b5b96398611427a1f929927e428",
"version" : "1.3.0"
}
},
{
"identity" : "dsfsparkline",
"kind" : "remoteSourceControl",
"location" : "https://github.com/dagronf/DSFSparkline.git",
"state" : {
"revision" : "cfcf80b9e214500cbc12b795b7c9943151b8bd4f",
"version" : "4.6.4"
}
},
{
"identity" : "flexiblediff",
"kind" : "remoteSourceControl",
"location" : "https://github.com/RACCommunity/FlexibleDiff",
"state" : {
"revision" : "a5132719a812111ef7eaea647a659a351b15abf4",
"version" : "0.0.9"
}
},
{
"identity" : "gzipswift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/1024jp/GzipSwift",
"state" : {
"revision" : "7a7f17761c76a932662ab77028a4329f67d645a4",
"version" : "5.2.0"
}
},
{
"identity" : "keyboardshortcuts",
"kind" : "remoteSourceControl",
"location" : "https://github.com/sindresorhus/KeyboardShortcuts",
"state" : {
"revision" : "018e445b340dac78dfc2a4c97c45d9571507c3b5",
"version" : "1.11.0"
}
},
{
"identity" : "nimble",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Quick/Nimble.git",
"state" : {
"revision" : "7a46a5fc86cb917f69e3daf79fcb045283d8f008",
"version" : "8.1.2"
}
},
{
"identity" : "promisekit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/mxcl/PromiseKit",
"state" : {
"revision" : "8a98e31a47854d3180882c8068cc4d9381bf382d",
"version" : "6.22.1"
}
},
{
"identity" : "quick",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Quick/Quick.git",
"state" : {
"revision" : "09b3becb37cb2163919a3842a4c5fa6ec7130792",
"version" : "2.2.1"
}
},
{
"identity" : "rxswift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/ReactiveX/RxSwift",
"state" : {
"revision" : "b4307ba0b6425c0ba4178e138799946c3da594f8",
"version" : "6.5.0"
}
},
{
"identity" : "starscream",
"kind" : "remoteSourceControl",
"location" : "https://github.com/daltoniam/Starscream",
"state" : {
"revision" : "e6b65c6d9077ea48b4a7bdda8994a1d3c6969c8d",
"version" : "3.1.1"
}
},
{
"identity" : "swift-log",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-log.git",
"state" : {
"revision" : "32e8d724467f8fe623624570367e3d50c5638e46",
"version" : "1.5.2"
}
},
{
"identity" : "swift-nio-zlib-support",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio-zlib-support.git",
"state" : {
"revision" : "37760e9a52030bb9011972c5213c3350fa9d41fd",
"version" : "1.0.0"
}
},
{
"identity" : "swiftui-introspect",
"kind" : "remoteSourceControl",
"location" : "https://github.com/siteline/SwiftUI-Introspect.git",
"state" : {
"revision" : "67e2a59be1cf1c6dc4bb7a861cbea888d423bb78",
"version" : "0.5.2"
}
},
{
"identity" : "swiftyjson",
"kind" : "remoteSourceControl",
"location" : "https://github.com/SwiftyJSON/SwiftyJSON",
"state" : {
"revision" : "b3dcd7dbd0d488e1a7077cb33b00f2083e382f07",
"version" : "5.0.1"
}
},
{
"identity" : "yams",
"kind" : "remoteSourceControl",
"location" : "https://github.com/jpsim/Yams",
"state" : {
"revision" : "f47ba4838c30dbd59998a4e4c87ab620ff959e8a",
"version" : "5.0.5"
}
}
],
"version" : 2
}

View File

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1420"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "49CF3B1C20CD7463001EBF94"
BuildableName = "ClashX Meta.app"
BlueprintName = "ClashX Meta"
ReferencedContainer = "container:ClashX SwiftUI.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "49CF3B1C20CD7463001EBF94"
BuildableName = "ClashX Meta.app"
BlueprintName = "ClashX Meta"
ReferencedContainer = "container:ClashX SwiftUI.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "49CF3B1C20CD7463001EBF94"
BuildableName = "ClashX Meta.app"
BlueprintName = "ClashX Meta"
ReferencedContainer = "container:ClashX SwiftUI.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 51;
objectVersion = 52;
objects = {
/* Begin PBXBuildFile section */
@ -16,16 +16,21 @@
019A239628657A7A00AE5698 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 019A239528657A7A00AE5698 /* main.swift */; };
01B009AE2854533300B93618 /* geoip.dat.gz in Resources */ = {isa = PBXBuildFile; fileRef = 01B009AC2854533200B93618 /* geoip.dat.gz */; };
01B009AF2854533300B93618 /* geosite.dat.gz in Resources */ = {isa = PBXBuildFile; fileRef = 01B009AD2854533300B93618 /* geosite.dat.gz */; };
01B1CB0A2A2E20C10073EA34 /* DashboardManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01B1CB092A2E20C10073EA34 /* DashboardManager.swift */; };
01B2274B29B845F100FE35C9 /* country.mmdb.gz in Resources */ = {isa = PBXBuildFile; fileRef = 01B2274A29B845F100FE35C9 /* country.mmdb.gz */; };
01BC9ABE2928EB5A00F9B177 /* MetaDNS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01BC9ABD2928E5C600F9B177 /* MetaDNS.swift */; };
01C1462A28962E4E00346AF3 /* com.metacubex.ClashX.ProxyConfigHelper.meta.gz in Resources */ = {isa = PBXBuildFile; fileRef = 01C1462928962E4E00346AF3 /* com.metacubex.ClashX.ProxyConfigHelper.meta.gz */; };
01E33AB229B5BF4200FD1006 /* NSColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01E33AB129B5BF4200FD1006 /* NSColor+Extension.swift */; };
01E33AB529B5C5E400FD1006 /* menu_icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 01E33AB429B5C5E300FD1006 /* menu_icon@2x.png */; };
185CBAEDFE986E6E1B836359 /* libPods-ClashX Meta.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AA63125BBF03DC1A291D3351 /* libPods-ClashX Meta.a */; };
4905A2C52A2058B000AEDA2E /* GlobalShortCutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4905A2C42A2058B000AEDA2E /* GlobalShortCutViewController.swift */; };
4905A2C82A2058D400AEDA2E /* KeyboardShortcuts in Frameworks */ = {isa = PBXBuildFile; productRef = 4905A2C72A2058D400AEDA2E /* KeyboardShortcuts */; };
4905A2CA2A20841B00AEDA2E /* NSView+Layout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4905A2C92A20841B00AEDA2E /* NSView+Layout.swift */; };
4908087B29F8F405007A4944 /* libresolv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 4908087A29F8F3FF007A4944 /* libresolv.tbd */; };
4913C82321157D0200F6B87C /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4913C82221157D0200F6B87C /* Notification.swift */; };
491E6203258A424D00313AEF /* CommonUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 491E61FD258A424500313AEF /* CommonUtils.m */; };
49228457270AADE20027A4B6 /* RemoteConfigUpdateIntervalSettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49228456270AADE20027A4B6 /* RemoteConfigUpdateIntervalSettingView.swift */; };
49281C802A1F01FA00F60935 /* DebugSettingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49281C7F2A1F01FA00F60935 /* DebugSettingViewController.swift */; };
4929F67F258CE04700A435F6 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4929F67E258CE04700A435F6 /* Settings.swift */; };
4929F684258CE07500A435F6 /* UserDefaultWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4929F683258CE07500A435F6 /* UserDefaultWrapper.swift */; };
492C4869210EE6B9004554A0 /* ApiRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 492C4868210EE6B9004554A0 /* ApiRequest.swift */; };
@ -79,6 +84,7 @@
49D176A72355FE680093DD7B /* NetworkChangeNotifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D176A62355FE680093DD7B /* NetworkChangeNotifier.swift */; };
49D176A9235614340093DD7B /* ProxyGroupSpeedTestMenuItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D176A8235614340093DD7B /* ProxyGroupSpeedTestMenuItem.swift */; };
49D176AB23575BB20093DD7B /* ProxyGroupMenuItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D176AA23575BB20093DD7B /* ProxyGroupMenuItemView.swift */; };
49D223392A1DA5F10002FFCB /* SSIDSuspendTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D223382A1DA5F10002FFCB /* SSIDSuspendTool.swift */; };
49D6A45229AEEC15006487EF /* StatusItemTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D6A45129AEEC15006487EF /* StatusItemTool.swift */; };
49D6A45429AEEC3C006487EF /* NewStatusItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D6A45329AEEC3C006487EF /* NewStatusItemView.swift */; };
49D6A45629AEEC55006487EF /* StatusItemViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D6A45529AEEC55006487EF /* StatusItemViewProtocol.swift */; };
@ -151,17 +157,21 @@
019A239528657A7A00AE5698 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
01B009AC2854533200B93618 /* geoip.dat.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = geoip.dat.gz; sourceTree = "<group>"; };
01B009AD2854533300B93618 /* geosite.dat.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = geosite.dat.gz; sourceTree = "<group>"; };
01B1CB092A2E20C10073EA34 /* DashboardManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashboardManager.swift; sourceTree = "<group>"; };
01B2274A29B845F100FE35C9 /* country.mmdb.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = country.mmdb.gz; sourceTree = "<group>"; };
01BC9ABD2928E5C600F9B177 /* MetaDNS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetaDNS.swift; sourceTree = "<group>"; };
01C1462928962E4E00346AF3 /* com.metacubex.ClashX.ProxyConfigHelper.meta.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = com.metacubex.ClashX.ProxyConfigHelper.meta.gz; sourceTree = "<group>"; };
01E33AB129B5BF4200FD1006 /* NSColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSColor+Extension.swift"; sourceTree = "<group>"; };
01E33AB429B5C5E300FD1006 /* menu_icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu_icon@2x.png"; sourceTree = "<group>"; };
3F86DA2DA3CC14731BE1ABF7 /* Pods-ClashX Meta.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ClashX Meta.release.xcconfig"; path = "Pods/Target Support Files/Pods-ClashX Meta/Pods-ClashX Meta.release.xcconfig"; sourceTree = "<group>"; };
4905A2C42A2058B000AEDA2E /* GlobalShortCutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalShortCutViewController.swift; sourceTree = "<group>"; };
4905A2C92A20841B00AEDA2E /* NSView+Layout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSView+Layout.swift"; sourceTree = "<group>"; };
4908087A29F8F3FF007A4944 /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; };
4913C82221157D0200F6B87C /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = "<group>"; };
491E61FC258A424500313AEF /* CommonUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommonUtils.h; sourceTree = "<group>"; };
491E61FD258A424500313AEF /* CommonUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CommonUtils.m; sourceTree = "<group>"; };
49228456270AADE20027A4B6 /* RemoteConfigUpdateIntervalSettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteConfigUpdateIntervalSettingView.swift; sourceTree = "<group>"; };
49281C7F2A1F01FA00F60935 /* DebugSettingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugSettingViewController.swift; sourceTree = "<group>"; };
4929F67E258CE04700A435F6 /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = "<group>"; };
4929F683258CE07500A435F6 /* UserDefaultWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDefaultWrapper.swift; sourceTree = "<group>"; };
492C4868210EE6B9004554A0 /* ApiRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiRequest.swift; sourceTree = "<group>"; };
@ -222,6 +232,7 @@
49D176A62355FE680093DD7B /* NetworkChangeNotifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkChangeNotifier.swift; sourceTree = "<group>"; };
49D176A8235614340093DD7B /* ProxyGroupSpeedTestMenuItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyGroupSpeedTestMenuItem.swift; sourceTree = "<group>"; };
49D176AA23575BB20093DD7B /* ProxyGroupMenuItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyGroupMenuItemView.swift; sourceTree = "<group>"; };
49D223382A1DA5F10002FFCB /* SSIDSuspendTool.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSIDSuspendTool.swift; sourceTree = "<group>"; };
49D6A45129AEEC15006487EF /* StatusItemTool.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusItemTool.swift; sourceTree = "<group>"; };
49D6A45329AEEC3C006487EF /* NewStatusItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewStatusItemView.swift; sourceTree = "<group>"; };
49D6A45529AEEC55006487EF /* StatusItemViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusItemViewProtocol.swift; sourceTree = "<group>"; };
@ -254,8 +265,6 @@
F977FAAB2366790500C17F1F /* AutoUpgardeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoUpgardeManager.swift; sourceTree = "<group>"; };
F977FAAD23669D6400C17F1F /* ConnectionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionManager.swift; sourceTree = "<group>"; };
F9A7C0692306E874007163C7 /* com.metacubex.ClashX.ProxyConfigHelper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = com.metacubex.ClashX.ProxyConfigHelper; sourceTree = BUILT_PRODUCTS_DIR; };
F9C180A1243C6590005EE8C4 /* goClash.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = goClash.a; path = ClashX/goClash/goClash.a; sourceTree = SOURCE_ROOT; };
F9C180A2243C6590005EE8C4 /* goClash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = goClash.h; path = ClashX/goClash/goClash.h; sourceTree = SOURCE_ROOT; };
F9E754CF239CC21F00CEE7CC /* WebPortalManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebPortalManager.swift; sourceTree = "<group>"; };
F9E754D1239CC28D00CEE7CC /* NSAlert+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSAlert+Extension.swift"; sourceTree = "<group>"; };
F9E8F34523A12B89002DE5E8 /* String+Encode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Encode.swift"; sourceTree = "<group>"; };
@ -268,6 +277,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
4905A2C82A2058D400AEDA2E /* KeyboardShortcuts in Frameworks */,
4908087B29F8F405007A4944 /* libresolv.tbd in Frameworks */,
185CBAEDFE986E6E1B836359 /* libPods-ClashX Meta.a in Frameworks */,
);
@ -317,6 +327,7 @@
493AEAE2221AE3420016FE98 /* AppVersionUtil.swift */,
49D176A62355FE680093DD7B /* NetworkChangeNotifier.swift */,
49B445152457CDF000B27E3E /* ClashStatusTool.swift */,
49D223382A1DA5F10002FFCB /* SSIDSuspendTool.swift */,
);
path = Utils;
sourceTree = "<group>";
@ -429,6 +440,7 @@
children = (
498BC2512929CC0A00CA8084 /* Settings */,
49BC061B212931F4005A0FE7 /* AboutViewController.swift */,
01B1CB092A2E20C10073EA34 /* DashboardManager.swift */,
499976C721359F0400E7BF83 /* ClashWebViewContoller.swift */,
499A485322ED707300F6C675 /* RemoteConfigViewController.swift */,
499ADAFE2498FC6D00C488FE /* ExternalControlViewController.swift */,
@ -441,6 +453,8 @@
children = (
498BC2522929CC2A00CA8084 /* SettingTabViewController.swift */,
498BC2542929CCAE00CA8084 /* GeneralSettingViewController.swift */,
49281C7F2A1F01FA00F60935 /* DebugSettingViewController.swift */,
4905A2C42A2058B000AEDA2E /* GlobalShortCutViewController.swift */,
);
path = Settings;
sourceTree = "<group>";
@ -451,6 +465,7 @@
495A44D220D267D000888A0A /* LaunchAtLogin.swift */,
4966E9E5211824F300A391FB /* NSImage+extension.swift */,
496BDEDF21196F1E00C5207F /* Logger.swift */,
4905A2C92A20841B00AEDA2E /* NSView+Layout.swift */,
49B10869216A356D0064FFCE /* String+Extension.swift */,
49ABB748236B0F9E00535CD7 /* UnsafePointer+bridge.swift */,
);
@ -516,8 +531,6 @@
49CF3B3A20CD783A001EBF94 /* Support Files */ = {
isa = PBXGroup;
children = (
F9C180A1243C6590005EE8C4 /* goClash.a */,
F9C180A2243C6590005EE8C4 /* goClash.h */,
4981C88D216BAE4A008CC14A /* Localizable.strings */,
);
path = "Support Files";
@ -594,7 +607,6 @@
49CF3B1A20CD7463001EBF94 /* Frameworks */,
49CF3B1B20CD7463001EBF94 /* Resources */,
663E4677213FCDC4006F11BB /* Copy Files */,
318032FABBC2E552CB58B254 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@ -602,6 +614,9 @@
F935B2EC2307B7CD009E4D33 /* PBXTargetDependency */,
);
name = "ClashX Meta";
packageProductDependencies = (
4905A2C72A2058D400AEDA2E /* KeyboardShortcuts */,
);
productName = ClashX;
productReference = 49CF3B1D20CD7463001EBF94 /* ClashX Meta.app */;
productType = "com.apple.product-type.application";
@ -661,6 +676,9 @@
"zh-Hans",
);
mainGroup = 49CF3B1420CD7463001EBF94;
packageReferences = (
4905A2C62A2058D400AEDA2E /* XCRemoteSwiftPackageReference "KeyboardShortcuts" */,
);
productRefGroup = 49CF3B1E20CD7463001EBF94 /* Products */;
projectDirPath = "";
projectRoot = "";
@ -713,23 +731,6 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
318032FABBC2E552CB58B254 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ClashX Meta/Pods-ClashX Meta-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ClashX Meta/Pods-ClashX Meta-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ClashX Meta/Pods-ClashX Meta-resources.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@ -744,6 +745,7 @@
4952C3D02117027C004A4FA8 /* ConfigFileManager.swift in Sources */,
49BC061C212931F4005A0FE7 /* AboutViewController.swift in Sources */,
4949D154213242F600EF85E6 /* Paths.swift in Sources */,
01B1CB0A2A2E20C10073EA34 /* DashboardManager.swift in Sources */,
499ADAFF2498FC6D00C488FE /* ExternalControlViewController.swift in Sources */,
F939724E23A4DB0600FE5A3F /* DateFormatter+.swift in Sources */,
F915A4622366ADEF004840BE /* ClashConnection.swift in Sources */,
@ -751,14 +753,17 @@
495340B320DE68C300B0D3FF /* StatusItemView.swift in Sources */,
F935B2FC23085515009E4D33 /* SystemProxyManager.swift in Sources */,
495A44D320D267D000888A0A /* LaunchAtLogin.swift in Sources */,
49281C802A1F01FA00F60935 /* DebugSettingViewController.swift in Sources */,
4929F67F258CE04700A435F6 /* Settings.swift in Sources */,
49D6A45629AEEC55006487EF /* StatusItemViewProtocol.swift in Sources */,
493AEAE3221AE3420016FE98 /* AppVersionUtil.swift in Sources */,
49CF3B2120CD7463001EBF94 /* AppDelegate.swift in Sources */,
496BDEE021196F1E00C5207F /* Logger.swift in Sources */,
4905A2CA2A20841B00AEDA2E /* NSView+Layout.swift in Sources */,
49722FEF211F338B00650A41 /* FileEvent.swift in Sources */,
016BEAB029D80103001586C5 /* AlphaMetaDownloader.swift in Sources */,
49D176A72355FE680093DD7B /* NetworkChangeNotifier.swift in Sources */,
4905A2C52A2058B000AEDA2E /* GlobalShortCutViewController.swift in Sources */,
4913C82321157D0200F6B87C /* Notification.swift in Sources */,
015F1E91288E42A50052B20A /* ClashMetaConfig.swift in Sources */,
8ACD21BD27A04ED500BC4632 /* ProxyModeChangeCommand.swift in Sources */,
@ -781,6 +786,7 @@
499A486522EEA3FD00F6C675 /* Array+Safe.swift in Sources */,
F92D0B24236BC12000575E15 /* SavedProxyModel.swift in Sources */,
F92D0B2A236C759100575E15 /* NSTextField+Vibrancy.swift in Sources */,
49D223392A1DA5F10002FFCB /* SSIDSuspendTool.swift in Sources */,
F910AA24240134AF00116E95 /* ProxyGroupMenu.swift in Sources */,
4952C3BF2115C7CA004A4FA8 /* MenuItemFactory.swift in Sources */,
49D6A45429AEEC3C006487EF /* NewStatusItemView.swift in Sources */,
@ -1182,6 +1188,25 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
4905A2C62A2058D400AEDA2E /* XCRemoteSwiftPackageReference "KeyboardShortcuts" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/sindresorhus/KeyboardShortcuts.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 1.0.0;
};
};
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
4905A2C72A2058D400AEDA2E /* KeyboardShortcuts */ = {
isa = XCSwiftPackageProductDependency;
package = 4905A2C62A2058D400AEDA2E /* XCRemoteSwiftPackageReference "KeyboardShortcuts" */;
productName = KeyboardShortcuts;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 49CF3B1520CD7463001EBF94 /* Project object */;
}

View File

@ -0,0 +1,149 @@
{
"pins" : [
{
"identity" : "alamofire",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Alamofire/Alamofire",
"state" : {
"revision" : "78424be314842833c04bc3bef5b72e85fff99204",
"version" : "5.6.4"
}
},
{
"identity" : "cocoalumberjack",
"kind" : "remoteSourceControl",
"location" : "https://github.com/CocoaLumberjack/CocoaLumberjack",
"state" : {
"revision" : "0188d31089b5881a269e01777be74c7316924346",
"version" : "3.8.0"
}
},
{
"identity" : "differencekit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/ra1028/DifferenceKit.git",
"state" : {
"revision" : "073b9671ce2b9b5b96398611427a1f929927e428",
"version" : "1.3.0"
}
},
{
"identity" : "dsfsparkline",
"kind" : "remoteSourceControl",
"location" : "https://github.com/dagronf/DSFSparkline.git",
"state" : {
"revision" : "cfcf80b9e214500cbc12b795b7c9943151b8bd4f",
"version" : "4.6.4"
}
},
{
"identity" : "flexiblediff",
"kind" : "remoteSourceControl",
"location" : "https://github.com/RACCommunity/FlexibleDiff",
"state" : {
"revision" : "a5132719a812111ef7eaea647a659a351b15abf4",
"version" : "0.0.9"
}
},
{
"identity" : "gzipswift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/1024jp/GzipSwift",
"state" : {
"revision" : "7a7f17761c76a932662ab77028a4329f67d645a4",
"version" : "5.2.0"
}
},
{
"identity" : "nimble",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Quick/Nimble.git",
"state" : {
"revision" : "7a46a5fc86cb917f69e3daf79fcb045283d8f008",
"version" : "8.1.2"
}
},
{
"identity" : "promisekit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/mxcl/PromiseKit",
"state" : {
"revision" : "8a98e31a47854d3180882c8068cc4d9381bf382d",
"version" : "6.22.1"
}
},
{
"identity" : "quick",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Quick/Quick.git",
"state" : {
"revision" : "09b3becb37cb2163919a3842a4c5fa6ec7130792",
"version" : "2.2.1"
}
},
{
"identity" : "rxswift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/ReactiveX/RxSwift",
"state" : {
"revision" : "b4307ba0b6425c0ba4178e138799946c3da594f8",
"version" : "6.5.0"
}
},
{
"identity" : "starscream",
"kind" : "remoteSourceControl",
"location" : "https://github.com/daltoniam/Starscream",
"state" : {
"revision" : "e6b65c6d9077ea48b4a7bdda8994a1d3c6969c8d",
"version" : "3.1.1"
}
},
{
"identity" : "swift-log",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-log.git",
"state" : {
"revision" : "32e8d724467f8fe623624570367e3d50c5638e46",
"version" : "1.5.2"
}
},
{
"identity" : "swift-nio-zlib-support",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio-zlib-support.git",
"state" : {
"revision" : "37760e9a52030bb9011972c5213c3350fa9d41fd",
"version" : "1.0.0"
}
},
{
"identity" : "swiftui-introspect",
"kind" : "remoteSourceControl",
"location" : "https://github.com/siteline/SwiftUI-Introspect.git",
"state" : {
"revision" : "5b3f3996c7a2a84d5f4ba0e03cd7d584154778f2",
"version" : "0.3.1"
}
},
{
"identity" : "swiftyjson",
"kind" : "remoteSourceControl",
"location" : "https://github.com/SwiftyJSON/SwiftyJSON",
"state" : {
"revision" : "b3dcd7dbd0d488e1a7077cb33b00f2083e382f07",
"version" : "5.0.1"
}
},
{
"identity" : "yams",
"kind" : "remoteSourceControl",
"location" : "https://github.com/jpsim/Yams",
"state" : {
"revision" : "f47ba4838c30dbd59998a4e4c87ab620ff959e8a",
"version" : "5.0.5"
}
}
],
"version" : 2
}

View File

@ -0,0 +1,14 @@
{
"pins" : [
{
"identity" : "keyboardshortcuts",
"kind" : "remoteSourceControl",
"location" : "https://github.com/sindresorhus/KeyboardShortcuts.git",
"state" : {
"revision" : "018e445b340dac78dfc2a4c97c45d9571507c3b5",
"version" : "1.11.0"
}
}
],
"version" : 2
}

View File

@ -8,7 +8,6 @@
import Alamofire
import Cocoa
import LetsMove
import RxCocoa
import RxSwift
import SwiftyJSON
@ -69,8 +68,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
var isSpeedTesting = false
var runAfterConfigReload: (() -> Void)?
var dashboardWindowController: ClashWebViewWindowController?
var helperStatusTimer: Timer?
@ -129,8 +126,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
PrivilegedHelperManager.shared.checkInstall()
ConfigFileManager.copySampleConfigIfNeed()
PFMoveToApplicationsFolderIfNecessary()
// claer not existed selected model
removeUnExistProxyGroups()
setupData()
@ -147,6 +142,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
setupNetworkNotifier()
registCrashLogger()
KeyboardShortCutManager.setup()
}
func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply {
@ -296,6 +292,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}
func setupData() {
SSIDSuspendTool.shared.setup()
ConfigManager.shared
.showNetSpeedIndicatorObservable.skip(1)
.bind {
@ -305,9 +302,11 @@ class AppDelegate: NSObject, NSApplicationDelegate {
Observable
.merge([ConfigManager.shared.proxyPortAutoSetObservable,
ConfigManager.shared.isProxySetByOtherVariable.asObservable()])
ConfigManager.shared.isProxySetByOtherVariable.asObservable(),
ConfigManager.shared.proxyShouldPaused.asObservable()])
.observe(on: MainScheduler.instance)
.map { _ -> NSControl.StateValue in
if ConfigManager.shared.isProxySetByOtherVariable.value && ConfigManager.shared.proxyPortAutoSet {
if (ConfigManager.shared.isProxySetByOtherVariable.value || ConfigManager.shared.proxyShouldPaused.value) && ConfigManager.shared.proxyPortAutoSet {
return .mixed
}
return ConfigManager.shared.proxyPortAutoSet ? .on : .off
@ -477,7 +476,9 @@ class AppDelegate: NSObject, NSApplicationDelegate {
.asObservable()
.filter { _ in ConfigManager.shared.proxyPortAutoSet }
.distinctUntilChanged()
.filter { $0 }.bind { _ in
.filter { $0 }
.filter { _ in !ConfigManager.shared.proxyShouldPaused.value }
.bind { _ in
let rawProxy = NetworkChangeNotifier.getRawProxySetting()
Logger.log("proxy changed to no clashX setting: \(rawProxy)", level: .warning)
NSUserNotificationCenter.default.postProxyChangeByOtherAppNotice()
@ -1013,15 +1014,8 @@ extension AppDelegate {
// MARK: Main actions
extension AppDelegate {
@IBAction func actionDashboard(_ sender: NSMenuItem) {
if dashboardWindowController == nil {
dashboardWindowController = ClashWebViewWindowController.create()
dashboardWindowController?.onWindowClose = {
[weak self] in
self?.dashboardWindowController = nil
}
}
dashboardWindowController?.showWindow(sender)
@IBAction func actionDashboard(_ sender: NSMenuItem?) {
DashboardManager.shared.show(sender)
}
@IBAction func actionAllowFromLan(_ sender: NSMenuItem) {
@ -1049,6 +1043,10 @@ extension AppDelegate {
default:
return
}
switchProxyMode(mode: mode)
}
func switchProxyMode(mode: ClashProxyMode) {
let config = ConfigManager.shared.currentConfig?.copy()
config?.mode = mode
ApiRequest.updateOutBoundMode(mode: mode) { _ in
@ -1062,9 +1060,11 @@ extension AppDelegate {
ConfigManager.shared.showNetSpeedIndicator = !(sender.state == .on)
}
@IBAction func actionSetSystemProxy(_ sender: Any) {
@IBAction func actionSetSystemProxy(_ sender: Any?) {
var canSaveProxy = true
if ConfigManager.shared.isProxySetByOtherVariable.value {
if ConfigManager.shared.proxyPortAutoSet && ConfigManager.shared.proxyShouldPaused.value {
ConfigManager.shared.proxyPortAutoSet = false
} else if ConfigManager.shared.isProxySetByOtherVariable.value {
// should reset proxy to clashx
ConfigManager.shared.isProxySetByOtherVariable.accept(false)
ConfigManager.shared.proxyPortAutoSet = true
@ -1149,7 +1149,7 @@ extension AppDelegate: ApiRequestStreamDelegate {
// MARK: Help actions
extension AppDelegate {
@IBAction func actionShowLog(_ sender: Any) {
@IBAction func actionShowLog(_ sender: Any?) {
NSWorkspace.shared.openFile(Logger.shared.logFilePath())
}
}

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="21507" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="21701" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21507"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21701"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
@ -12,6 +12,8 @@
<tabViewController title="Settings" showSeguePresentationStyle="single" selectedTabViewItemIndex="0" id="LAj-p8-9gd" customClass="SettingTabViewController" customModule="ClashX_Meta" customModuleProvider="target" sceneMemberID="viewController">
<tabViewItems>
<tabViewItem label="General" identifier="general" image="gearshape" catalog="system" id="Ltt-Vq-Hh1"/>
<tabViewItem image="keyboard" catalog="system" id="gnz-rO-Jv7"/>
<tabViewItem label="Debug" identifier="Debug" image="hammer" catalog="system" id="3Om-yT-A83"/>
</tabViewItems>
<tabView key="tabView" type="noTabsNoBorder" id="81C-Yt-rOb">
<rect key="frame" x="0.0" y="0.0" width="379" height="300"/>
@ -24,6 +26,8 @@
<connections>
<outlet property="tabView" destination="81C-Yt-rOb" id="lOZ-Kw-8VB"/>
<segue destination="kma-mp-ncL" kind="relationship" relationship="tabItems" id="sab-cs-oab"/>
<segue destination="wKZ-TE-sf8" kind="relationship" relationship="tabItems" id="T1L-JQ-EKQ"/>
<segue destination="kdV-Em-qBi" kind="relationship" relationship="tabItems" id="Mkx-Wo-vD6"/>
</connections>
</tabViewController>
<customObject id="bpW-G9-2N4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
@ -88,6 +92,185 @@
<constraint firstAttribute="bottom" secondItem="j6Y-mY-tCG" secondAttribute="bottom" constant="10" id="FDC-NY-hZH"/>
<constraint firstItem="j6Y-mY-tCG" firstAttribute="leading" secondItem="Lai-8r-q7z" secondAttribute="leading" constant="20" symbolic="YES" id="VQc-o1-puL"/>
<constraint firstItem="j6Y-mY-tCG" firstAttribute="top" secondItem="Lai-8r-q7z" secondAttribute="top" constant="10" id="fwo-Oq-R72"/>
<constraint firstAttribute="trailing" secondItem="j6Y-mY-tCG" secondAttribute="trailing" constant="20" symbolic="YES" id="xqH-sk-drO"/>
</constraints>
</view>
</box>
<box title="Port Settings (restart app to take effect)" translatesAutoresizingMaskIntoConstraints="NO" id="bcR-rG-52F">
<rect key="frame" x="-3" y="302" width="387" height="108"/>
<view key="contentView" id="baR-Ra-RV2">
<rect key="frame" x="4" y="5" width="379" height="88"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView distribution="fill" orientation="vertical" alignment="leading" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" verticalHuggingPriority="1000" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ito-5t-76A">
<rect key="frame" x="20" y="20" width="339" height="48"/>
<subviews>
<customView focusRingType="none" verticalHuggingPriority="1000" translatesAutoresizingMaskIntoConstraints="NO" id="1Qb-v8-TZs">
<rect key="frame" x="0.0" y="28" width="175" height="20"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="1000" translatesAutoresizingMaskIntoConstraints="NO" id="IZE-SM-zRM">
<rect key="frame" x="-2" y="2" width="71" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Proxy Port:" id="uUA-LS-Hu8">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mBx-6u-i5v">
<rect key="frame" x="75" y="0.0" width="100" height="20"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" usesSingleLineMode="YES" id="p2c-Ej-Ulq">
<numberFormatter key="formatter" formatterBehavior="default10_4" localizesFormat="NO" usesGroupingSeparator="NO" formatWidth="-1" groupingSize="0" minimumIntegerDigits="1" maximumIntegerDigits="42" id="I5q-Bi-gdc">
<real key="minimum" value="0.0"/>
<real key="maximum" value="65533"/>
</numberFormatter>
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstItem="IZE-SM-zRM" firstAttribute="centerY" secondItem="1Qb-v8-TZs" secondAttribute="centerY" id="6nb-Wb-Xb5"/>
<constraint firstItem="IZE-SM-zRM" firstAttribute="top" secondItem="1Qb-v8-TZs" secondAttribute="top" constant="2" id="OG0-Fw-2QJ"/>
<constraint firstAttribute="trailing" secondItem="mBx-6u-i5v" secondAttribute="trailing" id="SMN-Zb-3IV"/>
<constraint firstAttribute="bottom" secondItem="mBx-6u-i5v" secondAttribute="bottom" id="YQd-Qp-gmB"/>
<constraint firstItem="IZE-SM-zRM" firstAttribute="leading" secondItem="1Qb-v8-TZs" secondAttribute="leading" id="aBJ-lp-4il"/>
<constraint firstItem="mBx-6u-i5v" firstAttribute="top" secondItem="1Qb-v8-TZs" secondAttribute="top" id="e75-4a-nq1"/>
<constraint firstItem="mBx-6u-i5v" firstAttribute="leading" secondItem="IZE-SM-zRM" secondAttribute="trailing" constant="8" symbolic="YES" id="pvN-SY-NJX"/>
</constraints>
</customView>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="mmt-xm-hJE">
<rect key="frame" x="0.0" y="0.0" width="339" height="20"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="1000" translatesAutoresizingMaskIntoConstraints="NO" id="Ldb-qz-Xfv">
<rect key="frame" x="-2" y="2" width="57" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Api Port:" id="mbn-tK-UQa">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="xJH-gA-vcL">
<rect key="frame" x="75" y="0.0" width="100" height="20"/>
<constraints>
<constraint firstAttribute="width" priority="999" constant="100" id="T6o-oS-nw8"/>
</constraints>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" usesSingleLineMode="YES" id="pP3-Y0-7lW">
<numberFormatter key="formatter" formatterBehavior="default10_4" localizesFormat="NO" usesGroupingSeparator="NO" formatWidth="-1" groupingSize="0" minimumIntegerDigits="1" maximumIntegerDigits="42" id="8El-Kk-9qk">
<real key="minimum" value="0.0"/>
<real key="maximum" value="65533"/>
</numberFormatter>
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="uj5-FG-2x5">
<rect key="frame" x="181" y="1" width="158" height="18"/>
<buttonCell key="cell" type="check" title="Allow control from lan" bezelStyle="regularSquare" imagePosition="left" inset="2" id="E8B-e5-K0A">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
</subviews>
<constraints>
<constraint firstItem="xJH-gA-vcL" firstAttribute="top" secondItem="mmt-xm-hJE" secondAttribute="top" id="5iK-Hp-vxJ"/>
<constraint firstItem="xJH-gA-vcL" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Ldb-qz-Xfv" secondAttribute="trailing" constant="8" symbolic="YES" id="AcY-Zu-XgF"/>
<constraint firstItem="uj5-FG-2x5" firstAttribute="centerY" secondItem="mmt-xm-hJE" secondAttribute="centerY" id="Fdt-7c-Dbs"/>
<constraint firstAttribute="bottom" secondItem="xJH-gA-vcL" secondAttribute="bottom" id="Hf3-1g-PWM"/>
<constraint firstItem="uj5-FG-2x5" firstAttribute="leading" secondItem="xJH-gA-vcL" secondAttribute="trailing" constant="8" symbolic="YES" id="P65-hw-ZMT"/>
<constraint firstItem="Ldb-qz-Xfv" firstAttribute="top" secondItem="mmt-xm-hJE" secondAttribute="top" constant="2" id="XKY-eb-6G5"/>
<constraint firstItem="Ldb-qz-Xfv" firstAttribute="centerY" secondItem="mmt-xm-hJE" secondAttribute="centerY" id="kWK-cy-Pnt"/>
<constraint firstAttribute="trailing" secondItem="uj5-FG-2x5" secondAttribute="trailing" id="m5e-QK-DUa"/>
<constraint firstItem="Ldb-qz-Xfv" firstAttribute="leading" secondItem="mmt-xm-hJE" secondAttribute="leading" id="rjS-rN-Auf"/>
</constraints>
</customView>
</subviews>
<constraints>
<constraint firstItem="xJH-gA-vcL" firstAttribute="width" secondItem="mBx-6u-i5v" secondAttribute="width" id="cOy-tC-hkA"/>
<constraint firstItem="mBx-6u-i5v" firstAttribute="leading" secondItem="xJH-gA-vcL" secondAttribute="leading" id="crq-Fg-oyJ"/>
</constraints>
<visibilityPriorities>
<integer value="1000"/>
<integer value="1000"/>
</visibilityPriorities>
<customSpacing>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
</customSpacing>
</stackView>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="Ito-5t-76A" secondAttribute="trailing" constant="20" symbolic="YES" id="1z8-mZ-h84"/>
<constraint firstItem="Ito-5t-76A" firstAttribute="top" secondItem="baR-Ra-RV2" secondAttribute="top" constant="20" symbolic="YES" id="HrA-ZU-Vve"/>
<constraint firstItem="Ito-5t-76A" firstAttribute="leading" secondItem="baR-Ra-RV2" secondAttribute="leading" constant="20" symbolic="YES" id="NKY-E1-twt"/>
<constraint firstAttribute="bottom" secondItem="Ito-5t-76A" secondAttribute="bottom" constant="20" symbolic="YES" id="pjo-8o-eCg"/>
</constraints>
</view>
</box>
<box borderType="line" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="F94-On-Zm0">
<rect key="frame" x="-3" y="209" width="387" height="89"/>
<view key="contentView" id="icq-Gs-lyb">
<rect key="frame" x="4" y="5" width="379" height="81"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="dOk-QZ-mIx" userLabel="SSID Suspend">
<rect key="frame" x="18" y="55" width="343" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="SSID Suspend" id="F1s-SF-dqX">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="zlU-5G-cHf">
<rect key="frame" x="18" y="38" width="343" height="13"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Separated by commas(,)" id="xnL-ma-vFo">
<font key="font" textStyle="footnote" name=".SFNS-Regular"/>
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<scrollView borderType="none" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" translatesAutoresizingMaskIntoConstraints="NO" id="plI-7S-yCW">
<rect key="frame" x="20" y="10" width="339" height="20"/>
<clipView key="contentView" drawsBackground="NO" id="HHy-NP-pH6">
<rect key="frame" x="0.0" y="0.0" width="324" height="20"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textView importsGraphics="NO" richText="NO" verticallyResizable="YES" spellingCorrection="YES" smartInsertDelete="YES" id="sjz-uN-XpL">
<rect key="frame" x="0.0" y="0.0" width="324" height="20"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
<size key="minSize" width="324" height="20"/>
<size key="maxSize" width="339" height="10000000"/>
<color key="insertionPointColor" name="textColor" catalog="System" colorSpace="catalog"/>
</textView>
</subviews>
</clipView>
<constraints>
<constraint firstAttribute="height" constant="20" id="AAu-oE-zIa"/>
</constraints>
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="qzL-Bk-wjS">
<rect key="frame" x="-100" y="-100" width="225" height="15"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="OaY-Eu-ksx">
<rect key="frame" x="324" y="0.0" width="15" height="20"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="plI-7S-yCW" secondAttribute="trailing" constant="20" symbolic="YES" id="D3r-by-9PW"/>
<constraint firstItem="zlU-5G-cHf" firstAttribute="leading" secondItem="icq-Gs-lyb" secondAttribute="leading" constant="20" symbolic="YES" id="JRG-yy-VJ4"/>
<constraint firstItem="dOk-QZ-mIx" firstAttribute="leading" secondItem="icq-Gs-lyb" secondAttribute="leading" constant="20" symbolic="YES" id="QEv-iH-4jg"/>
<constraint firstItem="dOk-QZ-mIx" firstAttribute="top" secondItem="icq-Gs-lyb" secondAttribute="top" constant="10" id="SKH-zD-hcl"/>
<constraint firstItem="plI-7S-yCW" firstAttribute="top" secondItem="zlU-5G-cHf" secondAttribute="bottom" constant="8" symbolic="YES" id="TAv-Os-NGO"/>
<constraint firstItem="zlU-5G-cHf" firstAttribute="top" secondItem="dOk-QZ-mIx" secondAttribute="bottom" constant="4" id="clF-jD-KdB"/>
<constraint firstAttribute="trailing" secondItem="dOk-QZ-mIx" secondAttribute="trailing" constant="20" symbolic="YES" id="dBD-5Q-s4x"/>
<constraint firstAttribute="trailing" secondItem="zlU-5G-cHf" secondAttribute="trailing" constant="20" symbolic="YES" id="lxL-ue-f9G"/>
<constraint firstAttribute="bottom" secondItem="plI-7S-yCW" secondAttribute="bottom" constant="10" id="oVj-FL-cQg"/>
<constraint firstItem="plI-7S-yCW" firstAttribute="leading" secondItem="icq-Gs-lyb" secondAttribute="leading" constant="20" symbolic="YES" id="qfg-Lf-0sO"/>
</constraints>
</view>
</box>
@ -161,14 +344,20 @@
<constraints>
<constraint firstItem="Gnh-m8-PAz" firstAttribute="width" secondItem="VYa-DX-JOe" secondAttribute="width" id="FHq-ls-GZu"/>
<constraint firstItem="hnq-VC-kO5" firstAttribute="width" secondItem="VYa-DX-JOe" secondAttribute="width" id="kL7-uE-2XA"/>
<constraint firstItem="bcR-rG-52F" firstAttribute="leading" secondItem="VYa-DX-JOe" secondAttribute="leading" id="mWO-be-OEN"/>
<constraint firstItem="F94-On-Zm0" firstAttribute="width" secondItem="VYa-DX-JOe" secondAttribute="width" id="o3u-Hw-yEA"/>
</constraints>
<visibilityPriorities>
<integer value="1000"/>
<integer value="1000"/>
<integer value="1000"/>
<integer value="1000"/>
</visibilityPriorities>
<customSpacing>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
</customSpacing>
</stackView>
</subviews>
@ -180,9 +369,13 @@
</constraints>
</view>
<connections>
<outlet property="allowApiLanUsageSwitcher" destination="uj5-FG-2x5" id="wG9-3G-tAG"/>
<outlet property="apiPortTextField" destination="xJH-gA-vcL" id="C0N-be-EP1"/>
<outlet property="ignoreListTextView" destination="JDw-FW-A2o" id="fhs-QW-Ug6"/>
<outlet property="launchAtLoginButton" destination="jsq-3u-CRd" id="RnH-Va-nCX"/>
<outlet property="proxyPortTextField" destination="mBx-6u-i5v" id="Kaz-Ta-gPv"/>
<outlet property="reduceNotificationsButton" destination="6V3-wn-WSa" id="VtV-aI-dQi"/>
<outlet property="ssidSuspendTextField" destination="sjz-uN-XpL" id="jLA-M4-s5t"/>
<outlet property="useiCloudButton" destination="UGu-wD-xUs" id="VSD-og-kEv"/>
</connections>
</viewController>
@ -1387,9 +1580,214 @@
</objects>
<point key="canvasLocation" x="957" y="385.5"/>
</scene>
<!--Debug-->
<scene sceneID="uyL-8z-i0d">
<objects>
<viewController title="Debug" showSeguePresentationStyle="single" id="kdV-Em-qBi" customClass="DebugSettingViewController" customModule="ClashX" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" id="mud-rj-Isy">
<rect key="frame" x="0.0" y="0.0" width="416" height="197"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<box title="Debug Setting" translatesAutoresizingMaskIntoConstraints="NO" id="NLT-FZ-48V">
<rect key="frame" x="17" y="21" width="382" height="156"/>
<view key="contentView" id="JPj-NU-Cwp">
<rect key="frame" x="4" y="5" width="374" height="136"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView distribution="fillProportionally" orientation="vertical" alignment="leading" spacing="20" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="1000" horizontalHuggingPriority="1000" verticalHuggingPriority="1000" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6bh-Rg-qaG">
<rect key="frame" x="20" y="20" width="334" height="96"/>
<subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="CUS-EE-bqd">
<rect key="frame" x="-2" y="79" width="336" height="18"/>
<buttonCell key="cell" type="check" title="Use SwiftUI to render status bar icon. (MacOS 13+)" bezelStyle="regularSquare" imagePosition="left" inset="2" id="eY9-1i-i7P">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<stackView distribution="fill" orientation="horizontal" alignment="top" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="BPB-SW-GgH">
<rect key="frame" x="0.0" y="40" width="240" height="20"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="FdV-ph-XP8">
<rect key="frame" x="-2" y="4" width="82" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Proxy Helper" id="aSG-9A-eeG">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="tk3-Vg-1aq">
<rect key="frame" x="79" y="-7" width="168" height="32"/>
<buttonCell key="cell" type="push" title="Uninstall Proxy Helper" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="AY0-nP-cGT">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="actionUnInstallProxyHelper:" target="kdV-Em-qBi" id="GzM-BT-c1B"/>
</connections>
</button>
</subviews>
<visibilityPriorities>
<integer value="1000"/>
<integer value="1000"/>
</visibilityPriorities>
<customSpacing>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
</customSpacing>
</stackView>
<stackView distribution="fill" orientation="horizontal" alignment="top" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="pyT-RY-vER">
<rect key="frame" x="0.0" y="0.0" width="152" height="20"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="7Zc-tX-dnG">
<rect key="frame" x="-2" y="4" width="27" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Log" id="c01-0L-1SQ">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ewf-N4-Rnt">
<rect key="frame" x="24" y="-7" width="135" height="32"/>
<buttonCell key="cell" type="push" title="Open Log Folder" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="afj-4G-usr">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="actionOpenLogFolder:" target="kdV-Em-qBi" id="tcD-1m-wiT"/>
</connections>
</button>
</subviews>
<visibilityPriorities>
<integer value="1000"/>
<integer value="1000"/>
</visibilityPriorities>
<customSpacing>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
</customSpacing>
</stackView>
</subviews>
<constraints>
<constraint firstAttribute="height" constant="96" id="85d-JE-GA8"/>
</constraints>
<visibilityPriorities>
<integer value="1000"/>
<integer value="1000"/>
<integer value="1000"/>
</visibilityPriorities>
<customSpacing>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
</customSpacing>
</stackView>
</subviews>
<constraints>
<constraint firstAttribute="bottom" secondItem="6bh-Rg-qaG" secondAttribute="bottom" constant="20" symbolic="YES" id="AiI-f9-1Oz"/>
<constraint firstAttribute="trailing" secondItem="6bh-Rg-qaG" secondAttribute="trailing" constant="20" symbolic="YES" id="LaJ-dM-Sgk"/>
<constraint firstItem="6bh-Rg-qaG" firstAttribute="top" secondItem="JPj-NU-Cwp" secondAttribute="top" constant="20" symbolic="YES" id="vKc-4v-7vk"/>
<constraint firstItem="6bh-Rg-qaG" firstAttribute="leading" secondItem="JPj-NU-Cwp" secondAttribute="leading" constant="20" symbolic="YES" id="xnr-Is-2JX"/>
</constraints>
</view>
</box>
</subviews>
<constraints>
<constraint firstItem="NLT-FZ-48V" firstAttribute="leading" secondItem="mud-rj-Isy" secondAttribute="leading" constant="20" symbolic="YES" id="8bb-eR-yGi"/>
<constraint firstAttribute="bottom" secondItem="NLT-FZ-48V" secondAttribute="bottom" constant="25" id="DkE-rE-7eE"/>
<constraint firstItem="NLT-FZ-48V" firstAttribute="top" secondItem="mud-rj-Isy" secondAttribute="top" constant="20" symbolic="YES" id="Yuz-2o-YVi"/>
<constraint firstAttribute="trailing" secondItem="NLT-FZ-48V" secondAttribute="trailing" constant="20" symbolic="YES" id="qCG-oX-pi3"/>
</constraints>
</view>
<connections>
<outlet property="swiftuiMenuBarButton" destination="CUS-EE-bqd" id="BTF-Gy-b56"/>
</connections>
</viewController>
<customObject id="1kx-60-xza" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="668" y="1482.5"/>
</scene>
<!--Global ShortCut-->
<scene sceneID="723-vr-5MK">
<objects>
<viewController title="Global ShortCut" showSeguePresentationStyle="single" id="wKZ-TE-sf8" customClass="GlobalShortCutViewController" customModule="ClashX" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" id="6Ss-22-m8j">
<rect key="frame" x="0.0" y="0.0" width="507" height="414"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView distribution="fill" orientation="vertical" alignment="leading" spacing="20" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Y2e-mg-7Hh">
<rect key="frame" x="20" y="20" width="467" height="374"/>
<subviews>
<box ambiguous="YES" title="Proxy" translatesAutoresizingMaskIntoConstraints="NO" id="BFE-Qq-B2H">
<rect key="frame" x="-3" y="118" width="473" height="256"/>
<view key="contentView" ambiguous="YES" id="zD3-a4-GtN">
<rect key="frame" x="4" y="5" width="465" height="236"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</view>
</box>
<box ambiguous="YES" title="Mode" translatesAutoresizingMaskIntoConstraints="NO" id="1d5-NL-UsJ">
<rect key="frame" x="-3" y="82" width="473" height="20"/>
<view key="contentView" ambiguous="YES" id="kTK-fR-GhL">
<rect key="frame" x="4" y="5" width="465" height="0.0"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</view>
</box>
<box ambiguous="YES" title="Other" translatesAutoresizingMaskIntoConstraints="NO" id="AMT-oc-r8A" userLabel="Other">
<rect key="frame" x="-3" y="46" width="473" height="20"/>
<view key="contentView" ambiguous="YES" id="lP6-io-wrz">
<rect key="frame" x="4" y="5" width="465" height="0.0"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</view>
</box>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="249" translatesAutoresizingMaskIntoConstraints="NO" id="b4I-7R-wVz">
<rect key="frame" x="-2" y="0.0" width="471" height="30"/>
<textFieldCell key="cell" alignment="left" title="Please ensure to address any potential shortcut conflicts. Global shortcuts take precedence over regular shortcuts." id="GGx-F2-7kE">
<font key="font" metaFont="cellTitle"/>
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstItem="1d5-NL-UsJ" firstAttribute="width" secondItem="Y2e-mg-7Hh" secondAttribute="width" id="MyX-kB-qEz"/>
<constraint firstItem="AMT-oc-r8A" firstAttribute="width" secondItem="Y2e-mg-7Hh" secondAttribute="width" id="cNr-dX-ERJ"/>
<constraint firstItem="BFE-Qq-B2H" firstAttribute="width" secondItem="Y2e-mg-7Hh" secondAttribute="width" id="vlG-7H-Rp4"/>
</constraints>
<visibilityPriorities>
<integer value="1000"/>
<integer value="1000"/>
<integer value="1000"/>
<integer value="1000"/>
</visibilityPriorities>
<customSpacing>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
</customSpacing>
</stackView>
</subviews>
<constraints>
<constraint firstItem="Y2e-mg-7Hh" firstAttribute="leading" secondItem="6Ss-22-m8j" secondAttribute="leading" constant="20" symbolic="YES" id="KmG-7U-z46"/>
<constraint firstAttribute="trailing" secondItem="Y2e-mg-7Hh" secondAttribute="trailing" constant="20" symbolic="YES" id="Ovw-YV-pOb"/>
<constraint firstItem="Y2e-mg-7Hh" firstAttribute="top" secondItem="6Ss-22-m8j" secondAttribute="top" constant="20" symbolic="YES" id="cJJ-kT-R1c"/>
<constraint firstAttribute="bottom" secondItem="Y2e-mg-7Hh" secondAttribute="bottom" constant="20" symbolic="YES" id="gbx-mT-npp"/>
</constraints>
</view>
<connections>
<outlet property="modeBoxView" destination="kTK-fR-GhL" id="D5n-YX-aya"/>
<outlet property="otherBoxView" destination="lP6-io-wrz" id="7w1-En-MEl"/>
<outlet property="proxyBox" destination="BFE-Qq-B2H" id="IG2-Fa-v80"/>
</connections>
</viewController>
<customObject id="dgl-Fi-8yX" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="893.5" y="1939"/>
</scene>
</scenes>
<resources>
<image name="AppIcon" width="128" height="128"/>
<image name="gearshape" catalog="system" width="16" height="16"/>
<image name="hammer" catalog="system" width="19" height="18"/>
<image name="keyboard" catalog="system" width="19" height="13"/>
</resources>
</document>

View File

@ -48,4 +48,8 @@ class Logger {
func logFilePath() -> String {
return fileLogger.logFileManager.sortedLogFilePaths.first ?? ""
}
func logFolder() -> String {
return fileLogger.logFileManager.logsDirectory
}
}

View File

@ -0,0 +1,55 @@
//
// Logger.swift
// ClashX
//
// Created by CYC on 2018/8/7.
// Copyright © 2018 yichengchen. All rights reserved.
//
import CocoaLumberjackSwift
import Foundation
class Logger {
static let shared = Logger()
var fileLogger: DDFileLogger = DDFileLogger()
private init() {
#if DEBUG
DDLog.add(DDOSLogger.sharedInstance)
#endif
// default time zone is "UTC"
let dataFormatter = DateFormatter()
dataFormatter.setLocalizedDateFormatFromTemplate("YYYY/MM/dd HH:mm:ss:SSS")
fileLogger.logFormatter = DDLogFileFormatterDefault.init(dateFormatter: dataFormatter)
fileLogger.rollingFrequency = TimeInterval(60 * 60 * 24) // 24 hours
fileLogger.logFileManager.maximumNumberOfLogFiles = 3
DDLog.add(fileLogger)
dynamicLogLevel = ConfigManager.selectLoggingApiLevel.toDDLogLevel()
}
private func logToFile(msg: String, level: ClashLogLevel) {
switch level {
case .debug, .silent:
DDLogDebug(msg)
case .error:
DDLogError(msg)
case .info:
DDLogInfo(msg)
case .warning:
DDLogWarn(msg)
case .unknow:
DDLogWarn(msg)
}
}
static func log(_ msg: String, level: ClashLogLevel = .info) {
shared.logToFile(msg: "[\(level.rawValue)] \(msg)", level: level)
}
func logFilePath() -> String {
return fileLogger.logFileManager.sortedLogFilePaths.first ?? ""
}
func logFolder() -> String {
return fileLogger.logFileManager.logsDirectory
}
}

View File

@ -0,0 +1,35 @@
//
// UIView+Layout.swift
// BilibiliLive
//
// Created by Etan Chen on 2021/4/4.
//
import AppKit
extension NSView {
@discardableResult
func makeConstraints(_ block: (NSView) -> [NSLayoutConstraint]) -> Self {
translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate(block(self))
return self
}
@discardableResult
func makeConstraintsToBindToSuperview(_ inset: NSEdgeInsets = .init(top: 0, left: 0, bottom: 0, right: 0)) -> Self {
return makeConstraints { [
$0.leftAnchor.constraint(equalTo: $0.superview!.leftAnchor, constant: inset.left),
$0.rightAnchor.constraint(equalTo: $0.superview!.rightAnchor, constant: -inset.right),
$0.topAnchor.constraint(equalTo: $0.superview!.topAnchor, constant: inset.top),
$0.bottomAnchor.constraint(equalTo: $0.superview!.bottomAnchor, constant: -inset.bottom),
] }
}
@discardableResult
func makeConstraintsBindToCenterOfSuperview() -> Self {
return makeConstraints { [
$0.centerXAnchor.constraint(equalTo: $0.superview!.centerXAnchor),
$0.centerYAnchor.constraint(equalTo: $0.superview!.centerYAnchor),
] }
}
}

View File

@ -77,6 +77,7 @@ class ConfigManager {
let proxyPortAutoSetObservable = UserDefaults.standard.rx.observe(Bool.self, "proxyPortAutoSet").map({ $0 ?? false })
var isProxySetByOtherVariable = BehaviorRelay<Bool>(value: false)
var proxyShouldPaused = BehaviorRelay<Bool>(value: false)
var isTunModeVariable = BehaviorRelay<Bool>(value: false)

View File

@ -88,10 +88,12 @@ extension PrivilegedHelperManager {
Thread.sleep(forTimeInterval: 5)
}
let script = """
launchctl remove \(PrivilegedHelperManager.machServiceName) || true
rm -rf /Library/LaunchDaemons/\(PrivilegedHelperManager.machServiceName).plist
rm -rf /Library/PrivilegedHelperTools/\(PrivilegedHelperManager.machServiceName)
/bin/launchctl remove \(PrivilegedHelperManager.machServiceName) || true
/usr/bin/killall -u root -9 \(PrivilegedHelperManager.machServiceName)
/bin/rm -rf /Library/LaunchDaemons/\(PrivilegedHelperManager.machServiceName).plist
/bin/rm -rf /Library/PrivilegedHelperTools/\(PrivilegedHelperManager.machServiceName)
"""
runScriptWithRootPermission(script: script)
}
}

View File

@ -36,4 +36,20 @@ enum Settings {
@UserDefault("disableMenubarNotice", defaultValue: false)
static var disableMenubarNotice: Bool
@UserDefault("proxyPort", defaultValue: 0)
static var proxyPort: Int
@UserDefault("apiPort", defaultValue: 0)
static var apiPort: Int
@UserDefault("apiPortAllowLan", defaultValue: false)
static var apiPortAllowLan: Bool
@UserDefault("disableSSIDList", defaultValue: [])
static var disableSSIDList:[String]
@UserDefault("useSwiftUiMenuBar", defaultValue: true)
static var useSwiftUiMenuBar: Bool
}

View File

@ -56,6 +56,10 @@ class SystemProxyManager: NSObject {
Logger.log("enableProxy fail: \(port) \(socksPort)", level: .error)
return
}
if SSIDSuspendTool.shared.shouldSuspend() {
Logger.log("not enableProxy due to ssid in disabled list", level: .info)
return
}
Logger.log("enableProxy", level: .debug)
helper?.enableProxy(withPort: Int32(port),
socksPort: Int32(socksPort),

View File

@ -8,6 +8,7 @@
import Cocoa
import SystemConfiguration
import CoreWLAN
class NetworkChangeNotifier {
static func start() {
@ -179,4 +180,8 @@ class NetworkChangeNotifier {
}
return allowIPV6 ? ipv6 : nil
}
static func getCurrentSSID() -> String? {
return CWWiFiClient.shared().interface()?.ssid()
}
}

View File

@ -0,0 +1,59 @@
//
// SSIDSuspendTool.swift
// ClashX Pro
//
// Created by yicheng on 2023/5/24.
// Copyright © 2023 west2online. All rights reserved.
//
import Foundation
import RxSwift
import RxCocoa
class SSIDSuspendTool {
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)
ConfigManager.shared
.proxyShouldPaused
.asObservable()
.distinctUntilChanged()
.filter { _ in ConfigManager.shared.proxyPortAutoSet }
.bind { pause in
if pause {
SystemProxyManager.shared.disableProxy()
} else {
SystemProxyManager.shared.enableProxy()
}
}.disposed(by: disposeBag)
update()
}
func update() {
if shouldSuspend() {
ConfigManager.shared.proxyShouldPaused.accept(true)
} else {
ConfigManager.shared.proxyShouldPaused.accept(false)
}
}
func shouldSuspend() -> Bool {
if let currentSSID = NetworkChangeNotifier.getCurrentSSID() {
return Settings.disableSSIDList.contains(currentSSID)
} else {
return false
}
}
}

View File

@ -46,6 +46,12 @@
/* No comment provided by engineer. */
"Config loading Fail!" = "Config loading Fail!";
/* No comment provided by engineer. */
"Copy Shell Command" = "Copy Shell Command";
/* No comment provided by engineer. */
"Copy Shell Command (External)" = "Copy Shell Command (External)";
/* No comment provided by engineer. */
"Continue" = "Continue";
@ -61,6 +67,9 @@
/* No comment provided by engineer. */
"Direct" = "Direct";
/* No comment provided by engineer. */
"Direct Mode" = "Direct Mode";
/* No comment provided by engineer. */
"Disable Restore Proxy Setting" = "Disable Restore Proxy Setting";
@ -88,6 +97,9 @@
/* No comment provided by engineer. */
"Global" = "Global";
/* No comment provided by engineer. */
"Global Mode" = "Global Mode";
/* No comment provided by engineer. */
"Good luck to you 🙃" = "Good luck to you 🙃";
@ -122,6 +134,15 @@
/* No comment provided by engineer. */
"OK" = "OK";
/* No comment provided by engineer. */
"Open Dashboard" = "Open Dashboard";
/* No comment provided by engineer. */
"Open Log" = "Open Log";
/* No comment provided by engineer. */
"Open Menu" = "Open Menu";
/* No comment provided by engineer. */
"Open System Login Item Setting" = "Open System Login Item Setting";
@ -170,6 +191,15 @@
/* No comment provided by engineer. */
"Rule" = "Rule";
/* No comment provided by engineer. */
"Rule Mode" = "Rule Mode";
/* No comment provided by engineer. */
"Script" = "Script";
/* No comment provided by engineer. */
"Script Mode" = "Script Mode";
/* No comment provided by engineer. */
"Should be a least 1 hour" = "Should be a least 1 hour";
@ -191,6 +221,9 @@
/* No comment provided by engineer. */
"Success!" = "Success!";
/* No comment provided by engineer. */
"System Proxy" = "System Proxy";
/* No comment provided by engineer. */
"System Proxy Changed" = "System Proxy Changed";

View File

@ -46,6 +46,12 @@
/* No comment provided by engineer. */
"Config loading Fail!" = "配置文件加载失败";
/* No comment provided by engineer. */
"Copy Shell Command" = "复制终端代理命令";
/* No comment provided by engineer. */
"Copy Shell Command (External)" = "复制终端代理命令(外部IP)";
/* No comment provided by engineer. */
"Continue" = "继续";
@ -61,6 +67,9 @@
/* No comment provided by engineer. */
"Direct" = "直连";
/* No comment provided by engineer. */
"Direct Mode" = "直接连接";
/* No comment provided by engineer. */
"Disable Restore Proxy Setting" = "关闭自动还原之前代理";
@ -88,6 +97,9 @@
/* No comment provided by engineer. */
"Global" = "全局";
/* No comment provided by engineer. */
"Global Mode" = "全局连接";
/* No comment provided by engineer. */
"Good luck to you 🙃" = "祝你好运 🙃";
@ -121,6 +133,15 @@
/* No comment provided by engineer. */
"OK" = "确定";
/* No comment provided by engineer. */
"Open Dashboard" = "打开控制台";
/* No comment provided by engineer. */
"Open Log" = "打开日志";
/* No comment provided by engineer. */
"Open Menu" = "打开菜单";
/* No comment provided by engineer. */
"Open System Login Item Setting" = "打开系统登录项设置";
@ -169,6 +190,15 @@
/* No comment provided by engineer. */
"Rule" = "规则";
/* No comment provided by engineer. */
"Rule Mode" = "规则判断";
/* No comment provided by engineer. */
"Script" = "脚本";
/* No comment provided by engineer. */
"Script Mode" = "脚本模式";
/* No comment provided by engineer. */
"Should be a least 1 hour" = "至少需要1小时间隔";
@ -190,6 +220,9 @@
/* No comment provided by engineer. */
"Success!" = "成功!";
/* No comment provided by engineer. */
"System Proxy" = "设置系统代理";
/* No comment provided by engineer. */
"System Proxy Changed" = "系统代理设置已修改";

View File

@ -0,0 +1,25 @@
//
// DashboardManagerSwiftUI.swift
// ClashX Meta
//
// Copyright © 2023 west2online. All rights reserved.
//
import Cocoa
class DashboardManager: NSObject {
static let shared = DashboardManager()
var dashboardWindowController: ClashWebViewWindowController?
func show(_ sender: NSMenuItem?) {
if dashboardWindowController == nil {
dashboardWindowController = ClashWebViewWindowController.create()
dashboardWindowController?.onWindowClose = {
[weak self] in
self?.dashboardWindowController = nil
}
}
dashboardWindowController?.showWindow(sender)
}
}

View File

@ -0,0 +1,48 @@
//
// DashboardManagerSwiftUI.swift
// ClashX Meta
//
// Copyright © 2023 west2online. All rights reserved.
//
import Cocoa
import RxSwift
import ClashX_Dashboard
class DashboardManager: NSObject {
private let disposeBag = DisposeBag()
private var inited = false
static let shared = DashboardManager()
override init() {
}
var dashboardWindowController: DashboardWindowController?
func show(_ sender: NSMenuItem?) {
if !inited {
inited = true
NotificationCenter.default.rx.notification(.configFileChange).bind {
[weak self] _ in
self?.dashboardWindowController?.reload()
}.disposed(by: disposeBag)
NotificationCenter.default.rx.notification(.reloadDashboard).bind {
[weak self] _ in
self?.dashboardWindowController?.reload()
}.disposed(by: disposeBag)
}
if dashboardWindowController == nil {
dashboardWindowController = DashboardWindowController.create()
dashboardWindowController?.onWindowClose = {
[weak self] in
self?.dashboardWindowController = nil
}
}
dashboardWindowController?.set(ConfigManager.apiUrl, secret: ConfigManager.shared.overrideSecret ?? ConfigManager.shared.apiSecret)
dashboardWindowController?.showWindow(sender)
}
}

View File

@ -0,0 +1,30 @@
//
// DebugSettingViewController.swift
// ClashX Pro
//
// Created by yicheng on 2023/5/25.
// Copyright © 2023 west2online. All rights reserved.
//
import AppKit
import RxSwift
class DebugSettingViewController: NSViewController {
@IBOutlet weak var swiftuiMenuBarButton: NSButton!
var disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
swiftuiMenuBarButton.isEnabled = false
swiftuiMenuBarButton.state = Settings.useSwiftUiMenuBar ? .on : .off
swiftuiMenuBarButton.rx.state.bind { state in
Settings.useSwiftUiMenuBar = state == .on
}.disposed(by: disposeBag)
}
@IBAction func actionUnInstallProxyHelper(_ sender: Any) {
PrivilegedHelperManager.shared.removeInstallHelper()
}
@IBAction func actionOpenLogFolder(_ sender: Any) {
NSWorkspace.shared.openFile(Logger.shared.logFolder())
}
}

View File

@ -16,6 +16,11 @@ class GeneralSettingViewController: NSViewController {
@IBOutlet weak var reduceNotificationsButton: NSButton!
@IBOutlet weak var useiCloudButton: NSButton!
@IBOutlet weak var allowApiLanUsageSwitcher: NSButton!
@IBOutlet weak var proxyPortTextField: NSTextField!
@IBOutlet weak var apiPortTextField: NSTextField!
@IBOutlet var ssidSuspendTextField: NSTextView!
var disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
@ -28,6 +33,16 @@ class GeneralSettingViewController: NSViewController {
Settings.proxyIgnoreList = arr
}.disposed(by: disposeBag)
ssidSuspendTextField.string = Settings.disableSSIDList.joined(separator: ",")
ssidSuspendTextField.rx
.string.debounce(.milliseconds(500), scheduler: MainScheduler.instance)
.map { $0.components(separatedBy: ",").filter {!$0.isEmpty} }
.subscribe { arr in
Settings.disableSSIDList = arr
SSIDSuspendTool.shared.update()
}.disposed(by: disposeBag)
LaunchAtLogin.shared.isEnableVirable
.map { $0 ? .on : .off }
.bind(to: launchAtLoginButton.rx.state)
@ -48,6 +63,35 @@ class GeneralSettingViewController: NSViewController {
reduceNotificationsButton.rx.state.map {$0 == .on }.subscribe {
Settings.disableNoti = $0
}.disposed(by: disposeBag)
if Settings.proxyPort > 0 {
proxyPortTextField.stringValue = "\(Settings.proxyPort)"
} else {
proxyPortTextField.stringValue = "\(ConfigManager.shared.currentConfig?.mixedPort ?? 0)"
}
if Settings.apiPort > 0 {
apiPortTextField.stringValue = "\(Settings.apiPort)"
} else {
apiPortTextField.stringValue = ConfigManager.shared.apiPort
}
proxyPortTextField.rx.text
.compactMap {$0}
.compactMap {Int($0)}
.bind {
Settings.proxyPort = $0
}.disposed(by: disposeBag)
apiPortTextField.rx.text
.compactMap {$0}
.compactMap {Int($0)}
.bind {
Settings.apiPort = $0
}.disposed(by: disposeBag)
allowApiLanUsageSwitcher.state = Settings.apiPortAllowLan ? .on : .off
allowApiLanUsageSwitcher.rx.state.bind { state in
Settings.apiPortAllowLan = state == .on
}.disposed(by: disposeBag)
}
}

View File

@ -0,0 +1,112 @@
//
// GlobalShortCutViewController.swift
// ClashX Pro
//
// Created by yicheng on 2023/5/26.
// Copyright © 2023 west2online. All rights reserved.
//
import AppKit
import KeyboardShortcuts
extension KeyboardShortcuts.Name {
static let toggleSystemProxyMode = Self("shortCut.toggleSystemProxyMode")
static let copyShellCommand = Self("shortCut.copyShellCommand")
static let copyExternalShellCommand = Self("shortCut.copyExternalShellCommand")
static let modeDirect = Self("shortCut.modeDirect")
static let modeRule = Self("shortCut.modeRule")
static let modeGlobal = Self("shortCut.modeGlobal")
static let log = Self("shortCut.log")
static let dashboard = Self("shortCut.dashboard")
static let openMenu = Self("shortCut.openMenu")
}
enum KeyboardShortCutManager {
static func setup() {
KeyboardShortcuts.onKeyUp(for: .toggleSystemProxyMode) {
AppDelegate.shared.actionSetSystemProxy(nil)
}
KeyboardShortcuts.onKeyUp(for: .copyShellCommand) {
AppDelegate.shared.actionCopyExportCommand(AppDelegate.shared.copyExportCommandMenuItem)
}
KeyboardShortcuts.onKeyUp(for: .copyExternalShellCommand) {
AppDelegate.shared.actionCopyExportCommand(AppDelegate.shared.copyExportCommandExternalMenuItem)
}
KeyboardShortcuts.onKeyUp(for: .modeDirect) {
AppDelegate.shared.switchProxyMode(mode: .direct)
}
KeyboardShortcuts.onKeyUp(for: .modeRule) {
AppDelegate.shared.switchProxyMode(mode: .rule)
}
KeyboardShortcuts.onKeyUp(for: .modeGlobal) {
AppDelegate.shared.switchProxyMode(mode: .global)
}
KeyboardShortcuts.onKeyUp(for: .log) {
AppDelegate.shared.actionShowLog(nil)
}
KeyboardShortcuts.onKeyUp(for: .dashboard) {
AppDelegate.shared.actionDashboard(nil)
}
KeyboardShortcuts.onKeyUp(for: .openMenu) {
AppDelegate.shared.statusItem.button?.performClick(nil)
}
}
}
class GlobalShortCutViewController: NSViewController {
@IBOutlet weak var proxyBox: NSBox!
@IBOutlet weak var modeBoxView: NSView!
@IBOutlet weak var otherBoxView: NSView!
override func viewDidLoad() {
super.viewDidLoad()
let systemProxy = KeyboardShortcuts.RecorderCocoa(for: .toggleSystemProxyMode)
let copyShellCommand = KeyboardShortcuts.RecorderCocoa(for: .copyShellCommand)
let copyShellCommandExternal = KeyboardShortcuts.RecorderCocoa(for: .copyExternalShellCommand)
addGridView(in: proxyBox.contentView!, with: [
[NSTextField(labelWithString: NSLocalizedString("System Proxy", comment: "")),systemProxy],
[NSTextField(labelWithString: NSLocalizedString("Copy Shell Command", comment: "")),copyShellCommand],
[NSTextField(labelWithString: NSLocalizedString("Copy Shell Command (External)", comment: "")),copyShellCommandExternal],
])
addGridView(in: modeBoxView, with: [
[NSTextField(labelWithString: NSLocalizedString("Direct Mode", comment: "")),KeyboardShortcuts.RecorderCocoa(for: .modeDirect)],
[NSTextField(labelWithString: NSLocalizedString("Rule Mode", comment: "")),KeyboardShortcuts.RecorderCocoa(for: .modeRule)],
[NSTextField(labelWithString: NSLocalizedString("Global Mode", comment: "")),KeyboardShortcuts.RecorderCocoa(for: .modeGlobal)],
])
addGridView(in: otherBoxView, with: [
[NSTextField(labelWithString: NSLocalizedString("Open Menu", comment: "")),KeyboardShortcuts.RecorderCocoa(for: .openMenu)],
[NSTextField(labelWithString: NSLocalizedString("Open Log", comment: "")),KeyboardShortcuts.RecorderCocoa(for: .log)],
[NSTextField(labelWithString: NSLocalizedString("Open Dashboard", comment: "")),KeyboardShortcuts.RecorderCocoa(for: .dashboard)],
])
}
func addGridView(in superView:NSView, with views: [[NSView]]) {
let gridView = NSGridView(views: views)
gridView.rowSpacing = 10
gridView.rowAlignment = .firstBaseline
superView.addSubview(gridView)
gridView.makeConstraintsToBindToSuperview(NSEdgeInsets(top: 12, left: 12, bottom: 12, right: 12))
gridView.setContentHuggingPriority(.required, for: .vertical)
gridView.setContentCompressionResistancePriority(.required, for: .vertical)
gridView.xPlacement = .trailing
gridView.column(at: 0).xPlacement = .leading
}
}

View File

@ -1,23 +0,0 @@
#import <Foundation/Foundation.h>
typedef void (^NStringCallback)(NSString *,NSString *);
typedef void (^IntCallback)(int64_t,int64_t);
extern NStringCallback logCallback;
extern IntCallback trafficCallback;
void clash_setLogBlock(NStringCallback block);
void clash_setTrafficBlock(IntCallback block);
static inline void sendLogToUI(char *s, char *level) {
@autoreleasepool {
if (logCallback) {
logCallback([NSString stringWithUTF8String:s], [NSString stringWithUTF8String:level]);
}
}
}
static inline void sendTrafficToUI(int64_t up, int64_t down) {
if (trafficCallback) {
trafficCallback(up, down);
}
}

View File

@ -1,10 +0,0 @@
#import "UIHelper.h"
NStringCallback logCallback;
IntCallback trafficCallback;
void clash_setLogBlock(NStringCallback block) {
logCallback = [block copy];
}
void clash_setTrafficBlock(IntCallback block) {
trafficCallback = [block copy];
}

View File

@ -1,55 +0,0 @@
import subprocess
import datetime
import plistlib
import os
def get_version():
with open('./go.mod') as file:
for line in file.readlines():
if "clash" in line and "ClashX" not in line:
return line.split("-")[-1].strip()[:6]
return "unknown"
def get_full_version():
with open('./go.mod') as file:
for line in file.readlines():
if "clash" in line and "ClashX" not in line:
return line.split(" ")[-1].strip()
def build_clash(version):
build_time = datetime.datetime.now().strftime("%Y-%m-%d-%H%M")
command = f"""CGO_CFLAGS=-mmacosx-version-min=10.12 \
CGO_LDFLAGS=-mmacosx-version-min=10.12 \
go build -trimpath -ldflags '-X "github.com/Dreamacro/clash/constant.Version={version}" \
-X "github.com/Dreamacro/clash/constant.BuildTime={build_time}"' \
-buildmode=c-archive -o goClash.a """
subprocess.check_output(command, shell=True)
def write_to_info(version):
path = "../info.plist"
with open(path, 'rb') as f:
contents = plistlib.load(f)
if not contents:
exit(-1)
contents["coreVersion"] = version
with open(path, 'wb') as f:
plistlib.dump(contents, f, sort_keys=False)
def run():
version = get_version()
print("current clash version:", version)
build_clash(version)
print("build static library complete!")
if os.environ.get("CI", False) or os.environ.get("GITHUB_ACTIONS", False):
print("writing info.plist")
write_to_info(version)
print("done")
if __name__ == "__main__":
run()

View File

@ -288,3 +288,66 @@
/* Class = "NSTextFieldCell"; title = "Separated by commas(,)"; ObjectID = "sfe-wu-UXp"; */
"sfe-wu-UXp.title" = "使用英文逗号(,)分隔";
/* Class = "NSButtonCell"; title = "Allow control from lan"; ObjectID = "E8B-e5-K0A"; */
"E8B-e5-K0A.title" = "允许局域网控制(不推荐)";
/* Class = "NSBox"; title = "Port Settings (restart app to take effect)"; ObjectID = "bcR-rG-52F"; */
"bcR-rG-52F.title" = "端口设置(重启应用生效)";
/* Class = "NSTextFieldCell"; title = "Api Port:"; ObjectID = "mbn-tK-UQa"; */
"mbn-tK-UQa.title" = "Api 端口";
/* Class = "NSTextFieldCell"; title = "Proxy Port:"; ObjectID = "uUA-LS-Hu8"; */
"uUA-LS-Hu8.title" = "代理端口";
/* Class = "NSButtonCell"; title = "Reset"; ObjectID = "yXh-2Y-aTS"; */
"yXh-2Y-aTS.title" = "重置";
/* Class = "NSBox"; title = "Box"; ObjectID = "Gnh-m8-PAz"; */
"Gnh-m8-PAz.title" = "Box";
/* Class = "NSTextFieldCell"; title = "SSID Suspend"; ObjectID = "F1s-SF-dqX"; */
"F1s-SF-dqX.title" = "在特定 WiFi SSID 下自动暂停";
/* Class = "NSTextFieldCell"; title = "Separated by commas(,)"; ObjectID = "xnL-ma-vFo"; */
"xnL-ma-vFo.title" = "使用英文逗号(,)分隔";
/* Class = "NSTabViewItem"; label = "Debug"; ObjectID = "3Om-yT-A83"; */
"3Om-yT-A83.label" = "调试";
/* Class = "NSBox"; title = "Debug Setting"; ObjectID = "NLT-FZ-48V"; */
"NLT-FZ-48V.title" = "调试设置";
/* Class = "NSButtonCell"; title = "Use SwiftUI to render status bar icon. (MacOS 13+)"; ObjectID = "eY9-1i-i7P"; */
"eY9-1i-i7P.title" = "使用 SwiftUI 进行菜单栏图标渲染 (MacOS 13+)";
/* Class = "NSViewController"; title = "Debug"; ObjectID = "kdV-Em-qBi"; */
"kdV-Em-qBi.title" = "调试";
/* Class = "NSBox"; title = "Mode"; ObjectID = "1d5-NL-UsJ"; */
"1d5-NL-UsJ.title" = "代理模式";
/* Class = "NSBox"; title = "Other"; ObjectID = "AMT-oc-r8A"; */
"AMT-oc-r8A.title" = "其他";
/* Class = "NSBox"; title = "Proxy"; ObjectID = "BFE-Qq-B2H"; */
"BFE-Qq-B2H.title" = "代理设置";
/* Class = "NSViewController"; title = "Global ShortCut"; ObjectID = "wKZ-TE-sf8"; */
"wKZ-TE-sf8.title" = "全局快捷键";
/* Class = "NSTextFieldCell"; title = "Please ensure to address any potential shortcut conflicts. Global shortcuts take precedence over regular shortcuts."; ObjectID = "GGx-F2-7kE"; */
"GGx-F2-7kE.title" = "请务必注意处理可能存在的快捷键冲突,全局快捷键将优先于普通快捷键。";
/* Class = "NSButtonCell"; title = "Uninstall Proxy Helper"; ObjectID = "AY0-nP-cGT"; */
"AY0-nP-cGT.title" = "移除助手程序";
/* Class = "NSTextFieldCell"; title = "Proxy Helper"; ObjectID = "aSG-9A-eeG"; */
"aSG-9A-eeG.title" = "助手程序";
/* Class = "NSButtonCell"; title = "Open Log Folder"; ObjectID = "afj-4G-usr"; */
"afj-4G-usr.title" = "打开日志文件夹";
/* Class = "NSTextFieldCell"; title = "Log"; ObjectID = "c01-0L-1SQ"; */
"c01-0L-1SQ.title" = "日志";

View File

@ -1,5 +1,7 @@
source 'https://cdn.cocoapods.org/'
project 'ClashX.xcodeproj'
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
@ -16,7 +18,6 @@ end
target 'ClashX Meta' do
inhibit_all_warnings!
use_modular_headers!
pod 'LetsMove'
pod 'Alamofire', '~> 5.0'
pod 'SwiftyJSON'
pod 'RxSwift'

View File

@ -1,11 +1,10 @@
PODS:
- Alamofire (5.6.4)
- Alamofire (5.7.1)
- CocoaLumberjack/Core (3.8.0)
- CocoaLumberjack/Swift (3.8.0):
- CocoaLumberjack/Core
- FlexibleDiff (0.0.9)
- GzipSwift (5.1.1)
- LetsMove (1.25)
- PromiseKit (6.18.1):
- PromiseKit/CorePromise (= 6.18.1)
- PromiseKit/Foundation (= 6.18.1)
@ -29,7 +28,6 @@ DEPENDENCIES:
- CocoaLumberjack/Swift
- FlexibleDiff
- GzipSwift
- LetsMove
- PromiseKit (~> 6.8)
- RxCocoa
- RxSwift
@ -44,7 +42,6 @@ SPEC REPOS:
- CocoaLumberjack
- FlexibleDiff
- GzipSwift
- LetsMove
- PromiseKit
- RxCocoa
- RxRelay
@ -55,11 +52,10 @@ SPEC REPOS:
- Yams
SPEC CHECKSUMS:
Alamofire: 4e95d97098eacb88856099c4fc79b526a299e48c
Alamofire: 0123a34370cb170936ae79a8df46cc62b2edeb88
CocoaLumberjack: 78abfb691154e2a9df8ded4350d504ee19d90732
FlexibleDiff: b9ee9b8305b42c784f5dd40589203c97c55bbaa0
GzipSwift: 893f3e48e597a1a4f62fafcb6514220fcf8287fa
LetsMove: 7b9fe44737707d984fbd3f47af46609a9a07b461
PromiseKit: 49d70c53d5d20e346beaea4b276b5dd2ab446bb4
RxCocoa: 94f817b71c07517321eb4f9ad299112ca8af743b
RxRelay: 1de1523e604c72b6c68feadedd1af3b1b4d0ecbd
@ -69,6 +65,6 @@ SPEC CHECKSUMS:
WebViewJavascriptBridge: 7f5bc4d3581e672e8f32bd0f812d54bc69bb8e29
Yams: 271b5757cee031e087ae6322128895c04826c4f3
PODFILE CHECKSUM: 0c4cc178a9e07977b92df8cdd5f17ae3f4c2cc12
PODFILE CHECKSUM: 9106cf405ff39a4b995c7370bee60e8f7076b234
COCOAPODS: 1.12.1

View File

@ -9,6 +9,11 @@
A rule based proxy For Mac base on [Clash Meta](https://github.com/MetaCubeX/Clash.Meta).
## 注意
- ClashX / ClashX Pro / ClashX Meta 只是一个代理工具,不提供任何代理服务器。如果服务器不可用或与服务器续费有关的问题,请与您的提供商联系。
- ClashX / ClashX Pro / ClashX Meta 目前并没有创建官网。凡是声称是 ClashX / ClashX Pro / ClashX Meta 官网的一定是骗子。
## Features
- Clash.Meta Core
@ -18,6 +23,7 @@ A rule based proxy For Mac base on [Clash Meta](https://github.com/MetaCubeX/Cla
You can download from [Release](https://github.com/MetaCubeX/Clash.Meta/releases) page
**在 [AppCenter](https://install.appcenter.ms/users/clashx/apps/clashx-pro/distribution_groups/public) 免费下载ClashX Pro版本支持增强模式以及更多Clash Premium Core特性。**
## Build
- Make sure have python3 and golang installed in your computer.
@ -99,5 +105,5 @@ script:
Note强烈不推荐这么做这可能导致clashx的很多重要错误提醒无法显示。
### 全局快捷键
- 设置详情点击 [全局快捷键](Shortcuts.md)
- 在菜单栏配置->更多配置中自定义对应功能的快捷键。需要1.116.1之后的版本)
- 使用AppleScript设置, 详情点击 [全局快捷键](Shortcuts.md)

View File

@ -27,15 +27,15 @@ rm -f ./ClashX/Resources/geoip.dat
rm -rf ./ClashX/Resources/dashboard
rm -f GeoLite2-Country.*
echo "install mmdb"
curl -LO https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/country.mmdb
curl -LO https://github.com/MetaCubeX/meta-rules-dat/raw/release/country.mmdb
gzip country.mmdb
mv country.mmdb.gz ./ClashX/Resources/country.mmdb.gz
echo "install geosite"
curl -LO https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat
curl -LO https://github.com/MetaCubeX/meta-rules-dat/raw/release/geosite.dat
gzip geosite.dat
mv geosite.dat.gz ./ClashX/Resources/geosite.dat.gz
echo "install geoip"
curl -LO https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat
curl -LO https://github.com/MetaCubeX/meta-rules-dat/raw/release/geoip.dat
gzip geoip.dat
mv geoip.dat.gz ./ClashX/Resources/geoip.dat.gz
echo "install dashboard"