Update On Thu Jul 18 20:32:03 CEST 2024

This commit is contained in:
github-action[bot]
2024-07-18 20:32:03 +02:00
parent 34ef1aed3f
commit e5c52d96ff
229 changed files with 23416 additions and 12327 deletions

View File

@@ -115,7 +115,6 @@
66193A8523EE45B200289B6A /* PreferenceRouting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferenceRouting.swift; sourceTree = "<group>"; };
66193A8823EE46BC00289B6A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = V2rayU/Base.lproj/PreferenceRouting.xib; sourceTree = SOURCE_ROOT; };
6625848E2AB746D500DFDC1E /* appdmg.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = appdmg.sh; sourceTree = "<group>"; };
662F0ACE2AB720C700884C17 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = ../en.lproj/PreferenceGeneral.strings; sourceTree = "<group>"; };
663F040525ED4B2C00687600 /* V2rayLaunch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = V2rayLaunch.swift; sourceTree = "<group>"; };
664666A021CBD6C60094F0B7 /* libPods-V2rayUTool.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libPods-V2rayUTool.a"; sourceTree = BUILT_PRODUCTS_DIR; };
664B95DD217062A500DBC941 /* Alamofire */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Alamofire; path = Pods/Alamofire; sourceTree = "<group>"; };
@@ -136,6 +135,9 @@
667ECE6F2A9A05EB009B00EC /* V2rayUTool */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = V2rayUTool; sourceTree = BUILT_PRODUCTS_DIR; };
667ECE712A9A05EC009B00EC /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
6683B1EA21C2AD1A004A1C5F /* pac */ = {isa = PBXFileReference; lastKnownFileType = folder; name = pac; path = Build/pac; sourceTree = "<group>"; };
66943A2E2C494D7900F79A2A /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/MainMenu.strings"; sourceTree = "<group>"; };
66943A302C494F4B00F79A2A /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "../zh-Hans.lproj/PreferenceAdvance.strings"; sourceTree = "<group>"; };
66943A322C49509800F79A2A /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "../zh-Hans.lproj/PreferenceGeneral.strings"; sourceTree = "<group>"; };
669468492C076C2800146109 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
66973EB621797719001FEA1E /* ServiceManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ServiceManagement.framework; path = System/Library/Frameworks/ServiceManagement.framework; sourceTree = SDKROOT; };
66A358672C39517F00914A25 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
@@ -147,14 +149,10 @@
66AD5330241496FF0070529C /* Shortcut.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Shortcut.m; sourceTree = "<group>"; };
66AD5333241496FF0070529C /* V2rayU-Bridging-header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "V2rayU-Bridging-header.h"; sourceTree = "<group>"; };
66BC2B88228C589E00FBB716 /* V2raySubscription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = V2raySubscription.swift; sourceTree = "<group>"; };
66C5B194240B58B8008A22CA /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = ../en.lproj/PreferenceAdvance.strings; sourceTree = "<group>"; };
66F07CF8236D79540088A4AE /* Ping.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Ping.swift; sourceTree = "<group>"; };
66F3029C22AAA0A600FCA4E2 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/MainMenu.strings"; sourceTree = "<group>"; };
66F3029D22AAA0A600FCA4E2 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/ConfigWindow.strings"; sourceTree = "<group>"; };
66F3029E22AAA0A600FCA4E2 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/QrcodeWindow.strings"; sourceTree = "<group>"; };
66F3029F22AAA0A600FCA4E2 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "../zh-Hans.lproj/PreferenceAbout.strings"; sourceTree = "<group>"; };
66F302A022AAA0A600FCA4E2 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "../zh-Hans.lproj/PreferenceAdvance.strings"; sourceTree = "<group>"; };
66F302A122AAA0A600FCA4E2 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "../zh-Hans.lproj/PreferenceGeneral.strings"; sourceTree = "<group>"; };
66F302A222AAA0A700FCA4E2 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "../zh-Hans.lproj/PreferencePac.strings"; sourceTree = "<group>"; };
66F302A322AAA0A700FCA4E2 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "../zh-Hans.lproj/PreferenceSubscription.strings"; sourceTree = "<group>"; };
66FEAD45217D75FC009DECF9 /* release.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = release.sh; sourceTree = "<group>"; };
@@ -431,7 +429,7 @@
};
buildConfigurationList = 664EB36C216C9A5E00B6AE0D /* Build configuration list for PBXProject "V2rayU" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
developmentRegion = "zh-Hans";
hasScannedForEncodings = 0;
knownRegions = (
en,
@@ -602,7 +600,7 @@
isa = PBXVariantGroup;
children = (
664EB379216C9A5F00B6AE0D /* Base */,
66F3029C22AAA0A600FCA4E2 /* zh-Hans */,
66943A2E2C494D7900F79A2A /* zh-Hans */,
);
name = MainMenu.xib;
sourceTree = "<group>";
@@ -647,8 +645,7 @@
isa = PBXVariantGroup;
children = (
6D6DFE1CDFAD9828F2FDE1A5 /* Base */,
66F302A022AAA0A600FCA4E2 /* zh-Hans */,
66C5B194240B58B8008A22CA /* en */,
66943A302C494F4B00F79A2A /* zh-Hans */,
);
name = PreferenceAdvance.strings;
sourceTree = "<group>";
@@ -666,8 +663,7 @@
isa = PBXVariantGroup;
children = (
6D6DF81E59907A2C7579BFE2 /* Base */,
66F302A122AAA0A600FCA4E2 /* zh-Hans */,
662F0ACE2AB720C700884C17 /* en */,
66943A322C49509800F79A2A /* zh-Hans */,
);
name = PreferenceGeneral.strings;
sourceTree = "<group>";

View File

@@ -1855,7 +1855,7 @@ Gw
<autoresizingMask key="autoresizingMask"/>
<clipView key="contentView" id="0rS-HW-TeI">
<rect key="frame" x="1" y="1" width="375" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textView importsGraphics="NO" richText="NO" verticallyResizable="YES" selectionGranularity="word" allowsUndo="YES" allowsNonContiguousLayout="YES" textCompletion="NO" smartInsertDelete="YES" id="dNK-7u-GUm">
<rect key="frame" x="0.0" y="0.0" width="379" height="480"/>

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21225" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21225"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22690"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@@ -35,7 +35,7 @@
<rect key="frame" x="0.0" y="0.0" width="620" height="288"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="J1i-ZE-yo0">
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="J1i-ZE-yo0">
<rect key="frame" x="7" y="262" width="143" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Local Sock Listen Port:" id="dy9-2h-EIe">
@@ -52,7 +52,7 @@
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<textField verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="uGr-b9-5AH">
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="uGr-b9-5AH">
<rect key="frame" x="175" y="260" width="56" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString=" 1080" drawsBackground="YES" id="cEB-VU-kcL">
@@ -68,7 +68,7 @@
<outlet property="delegate" destination="-2" id="GnE-8z-kEw"/>
</connections>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="C6N-2x-WVg">
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="C6N-2x-WVg">
<rect key="frame" x="175" y="197" width="56" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString=" 1087" drawsBackground="YES" id="U2E-Gk-3e0">
@@ -81,7 +81,7 @@
</allowedInputSourceLocales>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KVU-hf-JUt">
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KVU-hf-JUt">
<rect key="frame" x="10" y="199" width="140" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Local Http Listen Port:" id="Yih-X2-qBl">
@@ -90,7 +90,7 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Qhi-c3-FLP">
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Qhi-c3-FLP">
<rect key="frame" x="6" y="170" width="143" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Local Http Listen Host:" id="uWf-ty-nD8">
@@ -99,7 +99,7 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ewk-8l-6kh">
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ewk-8l-6kh">
<rect key="frame" x="115" y="142" width="34" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Mux:" id="aux-FG-ubc">
@@ -108,7 +108,7 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="13S-5w-YMH">
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="13S-5w-YMH">
<rect key="frame" x="175" y="138" width="56" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString=" 8" drawsBackground="YES" id="gO2-cn-1bj">
@@ -150,7 +150,7 @@
</menu>
</popUpButtonCell>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="JVs-KU-cs6">
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="JVs-KU-cs6">
<rect key="frame" x="16" y="79" width="133" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="V2ray Core Log level:" id="Ctq-lX-cuA">
@@ -159,7 +159,7 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ZNZ-uI-32p">
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ZNZ-uI-32p">
<rect key="frame" x="7" y="111" width="143" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Pac Server Listen Port:" id="you-iw-OS5">
@@ -168,7 +168,7 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="SRQ-zG-lEW">
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="SRQ-zG-lEW">
<rect key="frame" x="175" y="107" width="56" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString=" 1087" drawsBackground="YES" id="cs0-w0-4jp">
@@ -181,7 +181,7 @@
</allowedInputSourceLocales>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="lg2-WJ-rab">
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="lg2-WJ-rab">
<rect key="frame" x="4" y="232" width="146" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Local Sock Listen Host:" id="jwm-cF-Zeb">
@@ -190,7 +190,7 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="qLO-QQ-RCr">
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="qLO-QQ-RCr">
<rect key="frame" x="175" y="165" width="138" height="22"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" title="127.0.0.1" drawsBackground="YES" id="os8-UE-0fP">
@@ -199,7 +199,7 @@
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Rfo-X1-n77">
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Rfo-X1-n77">
<rect key="frame" x="174" y="227" width="138" height="22"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" title="127.0.0.1" drawsBackground="YES" id="az8-jb-B7A">
@@ -216,7 +216,7 @@
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="1Aj-RG-gYn">
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="1Aj-RG-gYn">
<rect key="frame" x="10" y="26" width="359" height="17"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Label" id="GyI-8o-VH6">

View File

@@ -182,6 +182,8 @@ class ConfigWindowController: NSWindowController, NSWindowDelegate, NSTabViewDel
self.serversTableView.reloadData()
// selected current row
self.serversTableView.selectRowIndexes(NSIndexSet(index: V2rayServer.count() - 1) as IndexSet, byExtendingSelection: false)
menuController.showServers()
}
break

View File

@@ -17,15 +17,15 @@ class MenuController: NSObject, NSMenuDelegate {
var statusItemClicked: (() -> Void)?
let lock = NSLock()
@IBOutlet weak var pacMode: NSMenuItem!
@IBOutlet weak var manualMode: NSMenuItem!
@IBOutlet weak var globalMode: NSMenuItem!
@IBOutlet weak var statusMenu: NSMenu!
@IBOutlet weak var toggleV2rayItem: NSMenuItem!
@IBOutlet weak var v2rayStatusItem: NSMenuItem!
@IBOutlet weak var serverItems: NSMenuItem!
@IBOutlet weak var newVersionItem: NSMenuItem!
@IBOutlet weak var routingMenu: NSMenuItem!
@IBOutlet var pacMode: NSMenuItem!
@IBOutlet var manualMode: NSMenuItem!
@IBOutlet var globalMode: NSMenuItem!
@IBOutlet var statusMenu: NSMenu!
@IBOutlet var toggleV2rayItem: NSMenuItem!
@IBOutlet var v2rayStatusItem: NSMenuItem!
@IBOutlet var serverItems: NSMenuItem!
@IBOutlet var newVersionItem: NSMenuItem!
@IBOutlet var routingMenu: NSMenuItem!
// when menu.xib loaded
override func awakeFromNib() {
@@ -37,14 +37,21 @@ class MenuController: NSObject, NSMenuDelegate {
// hide new version
newVersionItem.isHidden = true
showRouting()
// windowWillClose Notification
NotificationCenter.default.addObserver(self, selector: #selector(configWindowWillClose(notification:)), name: NSWindow.willCloseNotification, object: nil)
}
func setStatusOff() {
DispatchQueue.main.async {
self.v2rayStatusItem.title = "v2ray-core: Off" + (" (v" + appVersion + ")")
self.toggleV2rayItem.title = "Turn v2ray-core On"
if isMainland {
self.v2rayStatusItem.title = "v2ray-core: 已关闭" + (" (v" + appVersion + ")")
self.toggleV2rayItem.title = "开启 v2ray-core"
} else {
self.v2rayStatusItem.title = "v2ray-core: Off" + (" (v" + appVersion + ")")
self.toggleV2rayItem.title = "Turn v2ray-core On"
}
if let button = self.statusItem.button {
button.image = NSImage(named: NSImage.Name("IconOff"))
@@ -61,7 +68,6 @@ class MenuController: NSObject, NSMenuDelegate {
func setModeIcon(mode: RunMode) {
DispatchQueue.main.async {
var iconName = "IconOn"
switch mode {
@@ -92,8 +98,13 @@ class MenuController: NSObject, NSMenuDelegate {
func setStatusOn(mode: RunMode) {
DispatchQueue.main.async {
self.v2rayStatusItem.title = "v2ray-core: On" + (" (v" + appVersion + ")")
self.toggleV2rayItem.title = "Turn v2ray-core Off"
if isMainland {
self.v2rayStatusItem.title = "v2ray-core: 已启动" + (" (v" + appVersion + ")")
self.toggleV2rayItem.title = "关闭 v2ray-core"
} else {
self.v2rayStatusItem.title = "v2ray-core: On" + (" (v" + appVersion + ")")
self.toggleV2rayItem.title = "Turn v2ray-core Off"
}
self.setModeIcon(mode: mode)
UserDefaults.setBool(forKey: .v2rayTurnOn, value: true)
}
@@ -111,7 +122,7 @@ class MenuController: NSObject, NSMenuDelegate {
DispatchQueue.global().async {
self.lock.lock()
defer { self.lock.unlock() }
print("showServers")
let _subMenus = self.getServerMenus()
@@ -121,45 +132,48 @@ class MenuController: NSObject, NSMenuDelegate {
configWindow.reloadData()
}
}
self.showRouting();
}
func showRouting() {
DispatchQueue.global().async {
let rules = V2rayRoutings.all()
print("showRouting",rules)
let sumMenus = NSMenu()
// add Routing... menu and click event is goRouting
let routingMenuItem = NSMenuItem()
routingMenuItem.title = "Routing..."
routingMenuItem.target = self
routingMenuItem.action = #selector(self.goRouting(_:))
sumMenus.addItem(routingMenuItem)
// add separator menu item
let separator = NSMenuItem.separator()
sumMenus.addItem(separator)
// now add all rules
let routingRule = UserDefaults.get(forKey: .routingSelectedRule)
for rule in rules {
let menuItem = NSMenuItem()
menuItem.title = rule.remark
menuItem.target = self
menuItem.action = #selector(self.switchRouting(_:))
menuItem.representedObject = rule
menuItem.isEnabled = true
if rule.name == routingRule {
menuItem.state = NSControl.StateValue.on
}
sumMenus.addItem(menuItem)
}
print("showRouting",sumMenus)
// routingMenu
DispatchQueue.main.async {
self.routingMenu.submenu = sumMenus
}
}
let rules = V2rayRoutings.all()
// print("showRouting", rules)
let sumMenus = NSMenu()
// add Routing... menu and click event is goRouting
let routingMenuItem = NSMenuItem()
if isMainland {
routingMenuItem.title = "路由..."
} else {
routingMenuItem.title = "Routing..."
}
routingMenuItem.target = self
routingMenuItem.action = #selector(self.goRouting(_:))
sumMenus.addItem(routingMenuItem)
// add separator menu item
let separator = NSMenuItem.separator()
sumMenus.addItem(separator)
// now add all rules
let routingRule = UserDefaults.get(forKey: .routingSelectedRule)
for rule in rules {
let menuItem = NSMenuItem()
menuItem.title = rule.remark
menuItem.target = self
menuItem.action = #selector(self.switchRouting(_:))
menuItem.representedObject = rule
menuItem.isEnabled = true
if rule.name == routingRule {
menuItem.state = NSControl.StateValue.on
}
sumMenus.addItem(menuItem)
}
// print("showRouting", sumMenus)
// routingMenu
DispatchQueue.main.async {
self.routingMenu.submenu = sumMenus
}
}
}
func getServerMenus() -> NSMenu {
// default
let curSer = UserDefaults.get(forKey: .v2rayCurrentServerName)
@@ -170,10 +184,10 @@ class MenuController: NSObject, NSMenuDelegate {
var chooseGroup = ""
// for each
for item in V2rayServer.all() {
validCount+=1
let menuItem: NSMenuItem = self.buildServerItem(item: item, curSer: curSer)
validCount += 1
let menuItem: NSMenuItem = buildServerItem(item: item, curSer: curSer)
var groupTag: String = item.subscribe
if (groupTag.isEmpty) {
if groupTag.isEmpty {
groupTag = "default"
_subMenus.addItem(menuItem)
continue
@@ -192,7 +206,7 @@ class MenuController: NSObject, NSMenuDelegate {
}
// subscribe items
for (itemKey,menu) in groupMenus {
for (itemKey, menu) in groupMenus {
if itemKey == "default" {
continue
}
@@ -225,7 +239,7 @@ class MenuController: NSObject, NSMenuDelegate {
func buildServerItem(item: V2rayItem, curSer: String?) -> NSMenuItem {
let menuItem: NSMenuItem = NSMenuItem()
menuItem.title = getMenuServerTitle(item: item)
menuItem.action = #selector(self.switchServer(_:))
menuItem.action = #selector(switchServer(_:))
menuItem.representedObject = item
menuItem.target = self
menuItem.isEnabled = true
@@ -282,11 +296,11 @@ class MenuController: NSObject, NSMenuDelegate {
NSLog("switchRouting err")
return
}
UserDefaults.set(forKey: .routingSelectedRule, value: obj.name);
self.showRouting();
UserDefaults.set(forKey: .routingSelectedRule, value: obj.name)
showRouting()
V2rayLaunch.restartV2ray()
}
@IBAction func openConfig(_ sender: NSMenuItem) {
OpenConfigWindow()
}
@@ -295,10 +309,9 @@ class MenuController: NSObject, NSMenuDelegate {
guard let object = notification.object as? NSWindow else {
return
}
print("configWindowWillClose",object.title,object)
let allow_titles = ["V2rayU","About","Pac","Subscription","General","Advance","Dns","Routing"]
let allow_titles = ["V2rayU", "About", "Pac", "Subscription", "General", "Advance", "Dns", "Routing"]
if allow_titles.contains(object.title) {
showDock(state: false)
showDock(state: false)
}
}
@@ -318,7 +331,7 @@ class MenuController: NSObject, NSMenuDelegate {
UserDefaults.set(forKey: .runMode, value: RunMode.pac.rawValue)
V2rayLaunch.restartV2ray()
}
@IBAction func goRouting(_ sender: NSMenuItem) {
DispatchQueue.main.async {
preferencesWindowController.show(preferencePane: .routingTab)
@@ -365,7 +378,7 @@ class MenuController: NSObject, NSMenuDelegate {
NSPasteboard.general.setString(command, forType: NSPasteboard.PasteboardType.string)
// Show a toast notification.
noticeTip(title: "Export Command Copied.", informativeText: "")
noticeTip(title: "Export Command Copied.", informativeText: "")
}
@IBAction func scanQrcode(_ sender: NSMenuItem) {
@@ -420,7 +433,7 @@ func getMenuServerTitle(item: V2rayItem) -> String {
// littleSpace: 1,.
if speed.contains(".") || speed.contains("1") {
let littleSpaceCount = speed.filter({ $0 == "." }).count + speed.filter({ $0 == "1" }).count
spaceCnt = totalSpaceCnt - ((speed.count - littleSpaceCount) + Int((speed.count - littleSpaceCount)/2))
spaceCnt = totalSpaceCnt - ((speed.count - littleSpaceCount) + Int((speed.count - littleSpaceCount) / 2))
}
if speed.contains("-1ms") {
spaceCnt = 9

View File

@@ -6,6 +6,8 @@
// Copyright © 2019 yanue. All rights reserved.
//
import Foundation
// ping and choose fastest v2ray
var inPing = false
var inPingCurrent = false
@@ -14,51 +16,51 @@ var ping = PingSpeed()
let second: Double = 1000000
let pingURL = URL(string: "http://www.gstatic.com/generate_204")!
func getRandomPort() -> UInt16 {
return UInt16.random(in: 49152...65535)
}
class PingSpeed: NSObject {
let maxConcurrentTasks = 30
func pingAll() {
NSLog("ping start")
if inPing {
guard !inPing else {
NSLog("ping inPing")
return
}
// make sure core file
V2rayLaunch.checkV2rayCore()
// in ping
inPing = true
killAllPing()
let itemList = V2rayServer.all()
if itemList.count == 0 {
guard !itemList.isEmpty else {
NSLog("no items")
inPing = false
return
}
let langStr = Locale.current.languageCode
var pingTip: String = ""
if langStr == "en" {
pingTip = "Ping Speed - In Testing "
} else {
pingTip = "Ping Speed - 测试中"
}
let pingTip = isMainland ? "Ping Speed - In Testing" : "Ping Speed - 测试中"
menuController.setStatusMenuTip(pingTip: pingTip)
Task {
do {
try await pingTaskGroup(items: itemList)
} catch let error {
} catch {
NSLog("pingTaskGroup error: \(error)")
}
}
NSLog("pingAll")
}
func pingTaskGroup(items: [V2rayItem]) async throws {
func pingTaskGroup(items: [V2rayItem]) async throws {
let taskChunks = stride(from: 0, to: items.count, by: maxConcurrentTasks).map {
Array(items[$0..<min($0 + maxConcurrentTasks, items.count)])
}
NSLog("pingTaskGroup-start: taskChunks=\(taskChunks.count)")
for (i, chunk) in taskChunks.enumerated() {
NSLog("pingTaskGroup-start-\(i): count=\(chunk.count)")
try await withThrowingTaskGroup(of: Void.self) { group in
@@ -69,125 +71,94 @@ class PingSpeed: NSObject {
} catch {
NSLog("pingEachServer error: \(error)")
}
return
}
}
//
try await group.waitForAll()
}
NSLog("pingTaskGroup-end-\(i)")
}
NSLog("pingTaskGroup-end")
self.pingEnd()
pingEnd()
}
func pingEachServer(item: V2rayItem) async throws {
NSLog("pingEachServer: \(item.name) - \(item.remark)")
if !item.isValid {
return
}
// ping
guard item.isValid else { return }
let t = PingServer(item: item)
try await t.doPing()
}
func pingEnd() {
inPing = false
let langStr = Locale.current.languageCode
var pingTip: String = ""
if langStr == "en" {
pingTip = "Ping Speed"
} else {
pingTip = "Ping"
}
print("pingEnd", pingTip)
let pingTip = "Ping"
NSLog("pingEnd: \(pingTip)")
menuController.setStatusMenuTip(pingTip: pingTip)
menuController.showServers()
// kill
killAllPing()
}
}
class PingServer: NSObject, URLSessionDataDelegate {
var item: V2rayItem
var bindPort: UInt16 = 0
var jsonFile: String = ""
var process: Process = Process()
init(item: V2rayItem) {
self.item = item
super.init() // can actually be omitted in this example because will happen automatically.
super.init()
}
func doPing() async throws {
let (_, _bindPort) = getUsablePort(port: uint16(Int.random(in: 9000 ... 36500)))
NSLog("doPing: \(item.name)-\(item.remark) - \(_bindPort)")
bindPort = _bindPort
bindPort = getRandomPort()
let _json_file = ".\(item.name).json"
jsonFile = AppHomePath + "/" + _json_file
// create v2ray config file
createV2rayJsonFileForPing()
//
let processPipe = Pipe()
// Create a Process instance with async launch
// use `/bin/bash -c cmd ...` and need kill subprocess
let pingCmd = "cd \(AppHomePath) && ./v2ray-core/v2ray run -config \(_json_file)"
NSLog("pingCmd: \(pingCmd)")
process.launchPath = "/bin/bash"
process.arguments = ["-c", pingCmd]
process.standardError = processPipe
process.standardOutput = processPipe
process.terminationHandler = { _process in
//
if _process.terminationStatus != EXIT_SUCCESS {
NSLog("process is not kill \(_bindPort) - \(_process.description) - \(_process.processIdentifier) - \(_process.terminationStatus)")
NSLog("process is not kill \(self.bindPort) - \(_process.description) - \(_process.processIdentifier) - \(_process.terminationStatus)")
_process.terminate()
_process.waitUntilExit()
}
}
// async launch and can't waitUntilExit
process.launch()
// sleep for wait v2ray process instanse
process.launch()
usleep(useconds_t(2 * second))
let session = URLSession(configuration: getProxyUrlSessionConfigure(httpProxyPort: bindPort), delegate: self, delegateQueue: nil)
do {
let (_,_) = try await session.data(for: URLRequest(url: pingURL))
} catch let error {
// failed to write file bad permissions, bad filename, missing permissions, or more likely it can't be converted to the encoding
_ = try await session.data(for: URLRequest(url: pingURL))
} catch {
NSLog("session request fail: \(error)")
}
}
func createV2rayJsonFileForPing() {
var jsonText = item.json
// parse old
let vCfg = V2rayConfig()
vCfg.enableSocks = false // just can use one tcp port
vCfg.enableSocks = false
vCfg.parseJson(jsonText: item.json)
vCfg.httpHost = "127.0.0.1"
vCfg.socksHost = "127.0.0.1"
vCfg.httpPort = String(bindPort)
vCfg.socksPort = String(bindPort + 1) // can't same with http port
// combine new default config
vCfg.socksPort = String(bindPort + 1)
jsonText = vCfg.combineManual()
do {
let jsonFilePath = URL(fileURLWithPath: jsonFile)
// delete before config
if FileManager.default.fileExists(atPath: jsonFile) {
try FileManager.default.removeItem(at: jsonFilePath)
}
// write
try jsonText.write(to: jsonFilePath, atomically: true, encoding: String.Encoding.utf8)
} catch let error {
// failed to write file bad permissions, bad filename, missing permissions, or more likely it can't be converted to the encoding
try jsonText.write(to: jsonFilePath, atomically: true, encoding: .utf8)
} catch {
NSLog("save json file fail: \(error)")
}
}
@@ -199,161 +170,163 @@ class PingServer: NSObject, URLSessionDataDelegate {
if let transactionMetrics = metrics.transactionMetrics.first {
let fetchStartDate = transactionMetrics.fetchStartDate
let responseEndDate = transactionMetrics.responseEndDate
// check
if responseEndDate != nil && fetchStartDate != nil {
let requestDuration = responseEndDate!.timeIntervalSince(fetchStartDate!)
if let fetchStartDate = fetchStartDate, let responseEndDate = responseEndDate {
let requestDuration = responseEndDate.timeIntervalSince(fetchStartDate)
let pingTs = Int(requestDuration * 100)
print("PingResult: fetchStartDate=\(fetchStartDate!),responseEndDate=\(responseEndDate!),requestDuration=\(requestDuration),pingTs=\(pingTs)")
// update ping speed
item.speed = String(format: "%d", pingTs) + "ms"
NSLog("PingResult: fetchStartDate=\(fetchStartDate), responseEndDate=\(responseEndDate), requestDuration=\(requestDuration), pingTs=\(pingTs)")
item.speed = String(format: "%dms", pingTs)
}
}
// save
item.store()
pingEnd()
}
func pingEnd() {
NSLog("ping end: \(item.remark) - \(item.speed)")
// delete config
do {
// exit process
if process.isRunning {
// terminate v2ray process
process.interrupt()
process.terminate()
process.waitUntilExit()
}
// close port
print("remove ping config:", jsonFile)
try FileManager.default.removeItem(at: URL(fileURLWithPath: jsonFile))
} catch let error {
print("remove ping config error: \(error)")
} catch {
NSLog("remove ping config error: \(error)")
}
}
}
class PingCurrent: NSObject, URLSessionDataDelegate {
var item: V2rayItem
var tryPing = 0
static let shared = PingCurrent()
init(item: V2rayItem) {
self.item = item
super.init() // can actually be omitted in this example because will happen automatically.
var item: V2rayItem?
var tryPing = 0
var inPingProcess = false
private override init() {
super.init()
}
func doPing() {
func startPing(with item: V2rayItem) {
guard !inPingProcess else {
return
}
self.item = item
tryPing = 0
doPing()
}
private func doPing() {
guard let item = item else { return }
inPingProcess = true
Task {
do {
try await _doPing()
pingCurrentEnd()
} catch let error {
} catch {
NSLog("doPing error: \(error)")
inPingProcess = false
}
}
}
func _doPing() async throws {
inPingCurrent = true
usleep(useconds_t(1 * second))
NSLog("PingCurrent start: try=\(tryPing),item=\(item.remark)")
// set URLSessionDataDelegate
private func _doPing() async throws {
usleep(useconds_t(1 * second)) // 1 second
guard let item = item else { return }
NSLog("PingCurrent start: try=\(tryPing), item=\(item.remark)")
let config = getProxyUrlSessionConfigure()
config.timeoutIntervalForRequest = 3
// url request
let session = URLSession(configuration: config, delegate: self, delegateQueue: nil)
tryPing += 1
do {
let (_,_) = try await session.data(for: URLRequest(url: pingURL))
} catch let error {
// failed to write file bad permissions, bad filename, missing permissions, or more likely it can't be converted to the encoding
let (_, _) = try await session.data(for: URLRequest(url: pingURL))
} catch {
NSLog("save json file fail: \(error)")
}
}
// MARK: - URLSessionDataDelegate
func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics) {
guard let item = item else { return }
item.speed = "-1ms"
if let transactionMetrics = metrics.transactionMetrics.first {
let fetchStartDate = transactionMetrics.fetchStartDate
let responseEndDate = transactionMetrics.responseEndDate
// check
if responseEndDate != nil && fetchStartDate != nil {
let requestDuration = responseEndDate!.timeIntervalSince(fetchStartDate!)
let pingTs = Int(requestDuration * 100)
print("PingCurrent: fetchStartDate=\(fetchStartDate!),responseEndDate=\(responseEndDate!),requestDuration=\(requestDuration),pingTs=\(pingTs)")
// update ping speed
item.speed = String(format: "%d", pingTs) + "ms"
}
if let transactionMetrics = metrics.transactionMetrics.first,
let fetchStartDate = transactionMetrics.fetchStartDate,
let responseEndDate = transactionMetrics.responseEndDate {
let requestDuration = responseEndDate.timeIntervalSince(fetchStartDate)
let pingTs = Int(requestDuration * 100)
print("PingCurrent: fetchStartDate=\(fetchStartDate), responseEndDate=\(responseEndDate), requestDuration=\(requestDuration), pingTs=\(pingTs)")
item.speed = "\(pingTs)ms"
}
// save
item.store()
}
func pingCurrentEnd() {
NSLog("PingCurrent end: try=\(tryPing),item=\(item.remark)")
// ping current fail
private func pingCurrentEnd() {
guard let item = item else { return }
NSLog("PingCurrent end: try=\(tryPing), item=\(item.remark)")
if item.speed == "-1ms" {
if tryPing < 3 {
usleep(useconds_t(3 * second))
doPing()
inPingProcess = false
DispatchQueue.global().asyncAfter(deadline: .now() + 3) {
self.doPing()
}
} else {
// choose next server
chooseNewServer()
}
} else {
inPingCurrent = false
inPingProcess = false
menuController.showServers()
}
}
func chooseNewServer() {
if !UserDefaults.getBool(forKey: .autoSelectFastestServer) {
NSLog(" - choose new server: disabled")
private func chooseNewServer() {
guard let item = item else {
inPingProcess = false
return
}
do {
let serverList = V2rayServer.all()
if serverList.count > 1 {
var pingedSvrs: Dictionary = [String: Int]()
var allSvrs = [String]()
for svr in serverList {
if svr.name == item.name {
continue
}
allSvrs.append(svr.name)
if svr.isValid && svr.speed != "-1ms" {
var speed = svr.speed
// suffix substring or not
let suffixStr = "ms"
if speed.hasSuffix(suffixStr) {
// Find the index to stop deleting at
let LIndex = speed.index(speed.endIndex, offsetBy: -suffixStr.count)
// Removing the suffix substring
speed = String(speed[..<LIndex])
}
pingedSvrs[svr.name] = Int(speed)
}
}
var newSvrName = ""
if pingedSvrs.count > 0 {
// sort by ping seed
let sortPing = pingedSvrs.sorted(by: { $0.value < $1.value })
newSvrName = sortPing[0].key
} else {
//
let idx = Int.random(in: 0 ... allSvrs.count-1)
newSvrName = allSvrs[idx]
}
NSLog(" - choose new server: \(newSvrName)")
// set current
UserDefaults.set(forKey: .v2rayCurrentServerName, value: newSvrName)
// restart
V2rayLaunch.restartV2ray()
}
inPingCurrent = false
guard UserDefaults.getBool(forKey: .autoSelectFastestServer) else {
NSLog(" - choose new server: disabled")
inPingProcess = false
return
}
let serverList = V2rayServer.all()
guard serverList.count > 1 else {
inPingProcess = false
return
}
var pingedSvrs = [String: Int]()
var allSvrs = [String]()
for svr in serverList where svr.name != item.name {
allSvrs.append(svr.name)
if svr.isValid && svr.speed != "-1ms" {
let speed = svr.speed.replacingOccurrences(of: "ms", with: "")
if let speedInt = Int(speed) {
pingedSvrs[svr.name] = speedInt
}
}
}
let newSvrName: String
if let fastestSvr = pingedSvrs.sorted(by: { $0.value < $1.value }).first {
newSvrName = fastestSvr.key
} else if let randomSvr = allSvrs.randomElement() {
newSvrName = randomSvr
} else {
inPingProcess = false
return
}
NSLog(" - choose new server: \(newSvrName)")
UserDefaults.set(forKey: .v2rayCurrentServerName, value: newSvrName)
V2rayLaunch.restartV2ray()
inPingProcess = false
}
}

View File

@@ -98,6 +98,8 @@ final class PreferenceRoutingViewController: NSViewController, PreferencePane, N
self.routingsTableView.reloadData()
// selected current row
self.routingsTableView.selectRowIndexes(NSIndexSet(index: V2rayRoutings.count() - 1) as IndexSet, byExtendingSelection: false)
// refresh menu
menuController.showRouting()
}
break
@@ -132,10 +134,10 @@ final class PreferenceRoutingViewController: NSViewController, PreferencePane, N
} else {
self.routingsTableView.becomeFirstResponder()
}
// refresh menu
menuController.showRouting()
}
// refresh menu
menuController.showRouting()
break
// unknown action

View File

@@ -557,6 +557,10 @@ func showDock(state: Bool) {
// Show / hide dock icon.
var psn = ProcessSerialNumber(highLongOfPSN: 0, lowLongOfPSN: UInt32(kCurrentProcess))
TransformProcessType(&psn, transformState)
if state {
// bring to front
NSApp.activate(ignoringOtherApps: true)
}
}
}

View File

@@ -36,8 +36,12 @@ func executeAppleScriptWithOsascript(script: String) {
print("executeAppleScript-Output: \(output)")
} catch {
print("executeAppleScript-Error: \(error)")
let title = NSLocalizedString("InstallFailedTitle", comment: "")
let toast = String(format: NSLocalizedString("InstallFailedMessage", comment: ""), error.localizedDescription, script)
var title = "Install V2rayUTool Failed";
var toast = "Error: \(error),\nYou need execute scripts manually:\n \(script)";
if isMainland {
title = "安装 V2rayUTool 失败"
toast = "安装失败: \(error)\n, 你需要在命令行手动执行一下: \(script)"
}
alertDialog(title: title, message: toast)
}
}
@@ -126,10 +130,18 @@ class V2rayLaunch: NSObject {
static func showInstallAlert() {
DispatchQueue.main.async {
let alert = NSAlert()
alert.messageText = NSLocalizedString("InstallAlertTitle", comment: "")
alert.alertStyle = .warning
alert.addButton(withTitle: NSLocalizedString("Install", comment: ""))
alert.addButton(withTitle: NSLocalizedString("Quit", comment: ""))
if isMainland {
alert.messageText = "安装V2rayUTool"
alert.informativeText = "V2rayU 需要使用管理员权限安装 V2rayUTool 到 ~/.V2rayU/V2rayUTool"
alert.addButton(withTitle: "安装")
alert.addButton(withTitle: "退出")
} else {
alert.messageText = " Install V2rayUTool"
alert.informativeText = "V2rayU needs to install V2rayUTool into ~/.V2rayU/V2rayUTool with administrator privileges"
alert.addButton(withTitle: "Install")
alert.addButton(withTitle: "Quit")
}
switch alert.runModal() {
case .alertFirstButtonReturn:
install()
@@ -266,7 +278,7 @@ class V2rayLaunch: NSObject {
menuController.showServers()
// ping current
PingCurrent(item: v2ray).doPing()
PingCurrent.shared.startPing(with: v2ray)
}
static func stopV2rayCore() {
@@ -289,13 +301,12 @@ class V2rayLaunch: NSObject {
// port has been used
if isPortOpen(port: httpPort) {
var toast = "http端口 \(httpPort) 已被使用, 请更换"
var title = "端口已被占用"
if Locale.current.languageCode == "en" {
toast = "http port \(httpPort) has been used, please replace it from advance setting"
title = "Port is already in use"
var toast = "http port \(httpPort) has been used, please replace it from advance setting"
var title = "Port is already in use"
if isMainland {
toast = "http端口 \(httpPort) 已被使用, 请更换"
title = "端口已被占用"
}
NSLocalizedString("", comment: "")
alertDialog(title: title, message: toast)
DispatchQueue.main.async {
preferencesWindowController.show(preferencePane: .advanceTab)
@@ -306,11 +317,11 @@ class V2rayLaunch: NSObject {
// port has been used
if isPortOpen(port: sockPort) {
var toast = "socks端口 \(sockPort) 已被使用, 请更换"
var title = "端口已被占用"
if Locale.current.languageCode == "en" {
toast = "socks port \(sockPort) has been used, please replace it from advance setting"
title = "Port is already in use"
var toast = "socks port \(sockPort) has been used, please replace it from advance setting"
var title = "Port is already in use"
if isMainland {
toast = "socks端口 \(sockPort) 已被使用, 请更换"
title = "端口已被占用"
}
alertDialog(title: title, message: toast)
DispatchQueue.main.async {
@@ -385,11 +396,11 @@ class V2rayLaunch: NSObject {
let pacPort = getPacPort()
// port has been used
if isPortOpen(port: pacPort) {
var toast = "pac端口 \(pacPort) 已被使用, 请更换"
var title = "端口已被占用"
if Locale.current.languageCode == "en" {
toast = "pac port \(pacPort) has been used, please replace from advance setting"
title = "Port is already in use"
var toast = "pac port \(pacPort) has been used, please replace from advance setting"
var title = "Port is already in use"
if isMainland {
toast = "pac端口 \(pacPort) 已被使用, 请更换"
title = "端口已被占用"
}
alertDialog(title: title, message: toast)
DispatchQueue.main.async {

View File

@@ -64,43 +64,8 @@ class V2rayRoutings: NSObject {
}
// static reset
self.routings = []
// load name list from UserDefaults
var list = UserDefaults.getArray(forKey: .routingCustomList) ?? [];
print("V2rayRoutings-loadConfig", list)
let langStr = Locale.current.languageCode
let isMainland = langStr == "zh-CN" || langStr == "zh" || langStr == "zh-Hans" || langStr == "zh-Hant"
// for defaultRules
for (key, rule) in defaultRules {
// load and check
if nil == RoutingItem.load(name: key) {
if isMainland {
rule.remark = defaultRuleCn[key] ?? rule.remark
} else {
rule.remark = defaultRuleEn[key] ?? rule.remark
}
// create new
rule.store()
}
// if not in list, append
if !list.contains(key) {
list.append(key)
}
}
// load each RoutingItem
for item in list {
guard let routing = RoutingItem.load(name: item) else {
// delete from UserDefaults
RoutingItem.remove(name: item)
continue
}
// append
self.routings.append(routing)
}
self.routings = V2rayRoutings.all()
self.saveItemList()
print("V2rayRoutings-loadConfig", self.routings.count)
}
@@ -118,20 +83,37 @@ class V2rayRoutings: NSObject {
var items : [RoutingItem] = []
// load name list from UserDefaults
var list = UserDefaults.getArray(forKey: .routingCustomList)
if list == nil {
list = []
}
var list = UserDefaults.getArray(forKey: .routingCustomList) ?? [];
// load each V2rayItem
for item in list! {
print("V2rayRoutings-loadConfig", list)
// for defaultRules
for (key, rule) in defaultRules {
// load and check
if nil == RoutingItem.load(name: key) {
if isMainland {
rule.remark = defaultRuleCn[key] ?? rule.remark
} else {
rule.remark = defaultRuleEn[key] ?? rule.remark
}
// create new
rule.store()
}
// if not in list, append
if !list.contains(key) {
list.append(key)
}
}
// load each RoutingItem
for item in list {
guard let routing = RoutingItem.load(name: item) else {
// delete from UserDefaults
RoutingItem.remove(name: item)
continue
}
// append
items.append(routing)
items.append(routing)
}
return items
}
@@ -211,7 +193,7 @@ class V2rayRoutings: NSObject {
// update server list UserDefaults
static func saveItemList() {
var routingCustomList: Array<String> = []
for item in V2rayRoutings.list() {
for item in self.routings {
routingCustomList.append(item.name)
}
@@ -455,7 +437,7 @@ class RoutingItem: NSObject, NSCoding {
}
}
print("ips", ips, "domains", domains)
// print("ips", ips, "domains", domains)
return (domains, ips)
}

View File

@@ -5,7 +5,3 @@
Created by yanue on 2019/7/17.
Copyright © 2019 yanue. All rights reserved.
*/
/* Alert titles */
"InstallAlertTitle" = "V2rayU needs to install V2rayUTool into ~/.V2rayU/V2rayUTool with administrator privileges";
"InstallFailedTitle" = "Install V2rayUTool Failed"
"InstallFailedMessage" = "Error: %s,\nYou need execute scripts manually:\n %s"

View File

@@ -5,6 +5,3 @@
Created by yanue on 2019/7/17.
Copyright © 2019 yanue. All rights reserved.
*/
"InstallAlertTitle" = "V2rayU 需要使用管理员权限安装 V2rayUTool 到 ~/.V2rayU/V2rayUTool";
"InstallFailedTitle" = "安装 V2rayUTool 失败"
"InstallFailedMessage" = "安装失败: %s\n, 你需要在命令行手动执行一下: %s"

View File

@@ -1,54 +1,57 @@
/* Class = "NSMenuItem"; title = "Generate QR Code"; ObjectID = "0vX-fS-8FW"; */
/* Class = "NSMenuItem"; title = "Share QR Code"; ObjectID = "0vX-fS-8FW"; */
"0vX-fS-8FW.title" = "分享二维码";
/* Class = "NSMenuItem"; title = "Make Lower Case"; ObjectID = "0zv-gA-dTG"; */
"0zv-gA-dTG.title" = "转换小写";
"0zv-gA-dTG.title" = "Make Lower Case";
/* Class = "NSMenuItem"; title = "Quit"; ObjectID = "28U-8z-8lS"; */
"28U-8z-8lS.title" = "退出";
/* Class = "NSMenuItem"; title = "Edit"; ObjectID = "2CF-Be-R2r"; */
"2CF-Be-R2r.title" = "编辑";
"2CF-Be-R2r.title" = "Edit";
/* Class = "NSMenuItem"; title = "Redo"; ObjectID = "2dI-3i-ukZ"; */
"2dI-3i-ukZ.title" = "重做";
"2dI-3i-ukZ.title" = "Redo";
/* Class = "NSMenuItem"; title = "Undo"; ObjectID = "2yB-5O-rLI"; */
"2yB-5O-rLI.title" = "撤销";
"2yB-5O-rLI.title" = "Undo";
/* Class = "NSMenuItem"; title = "Capitalize"; ObjectID = "3Hg-b3-phw"; */
"3Hg-b3-phw.title" = "转换大写";
"3Hg-b3-phw.title" = "Capitalize";
/* Class = "NSMenuItem"; title = "Show Logs..."; ObjectID = "52m-v5-TzY"; */
"52m-v5-TzY.title" = "查看v2ray日志";
/* Class = "NSMenuItem"; title = "View v2ray log"; ObjectID = "52m-v5-TzY"; */
"52m-v5-TzY.title" = "查看v2ray日志";
/* Class = "NSMenuItem"; title = "Smart Dashes"; ObjectID = "6aH-vb-Jom"; */
"6aH-vb-Jom.title" = "智能破折号";
"6aH-vb-Jom.title" = "Smart Dashes";
/* Class = "NSMenuItem"; title = "Preferences..."; ObjectID = "6jp-RJ-ww9"; */
"6jp-RJ-ww9.title" = "偏好设置";
"6jp-RJ-ww9.title" = "偏好设置...";
/* Class = "NSMenuItem"; title = "Speech"; ObjectID = "6ks-XF-0pf"; */
"6ks-XF-0pf.title" = "言语";
"6ks-XF-0pf.title" = "Speech";
/* Class = "NSMenuItem"; title = "Text Replacement"; ObjectID = "7EO-ax-Qem"; */
"7EO-ax-Qem.title" = "文本替换";
"7EO-ax-Qem.title" = "Text Replacement";
/* Class = "NSMenuItem"; title = "Smart Copy/Paste"; ObjectID = "7Fw-Hy-HhI"; */
"7Fw-Hy-HhI.title" = "智能复制/粘贴";
"7Fw-Hy-HhI.title" = "Smart Copy/Paste";
/* Class = "NSMenuItem"; title = "Pac..."; ObjectID = "8ps-CD-zNp"; */
"8ps-CD-zNp.title" = "Pac设置";
/* Class = "NSMenuItem"; title = "Select All"; ObjectID = "8zL-Er-HLk"; */
"8zL-Er-HLk.title" = "全选";
"8zL-Er-HLk.title" = "Select All";
/* Class = "NSMenu"; title = "V2rayU"; ObjectID = "9n3-TW-9ur"; */
"9n3-TW-9ur.title" = "V2rayU";
/* Class = "NSMenuItem"; title = "Use Selection for Find"; ObjectID = "9rd-LX-kku"; */
"9rd-LX-kku.title" = "从选中文本查找";
"9rd-LX-kku.title" = "Use Selection for Find";
/* Class = "NSMenuItem"; title = "Ping Speed..."; ObjectID = "A9g-Ks-No1"; */
"A9g-Ks-No1.title" = "Ping速度";
/* Class = "NSMenuItem"; title = "Check Document Now"; ObjectID = "BQD-PL-x7i"; */
"BQD-PL-x7i.title" = "Check Document Now";
@@ -66,13 +69,13 @@
"JuC-lf-LpQ.title" = "订阅设置";
/* Class = "NSMenuItem"; ibShadowedToolTip = "ss:// or vmess://"; ObjectID = "Kct-KD-qPN"; */
"Kct-KD-qPN.ibShadowedToolTip" = "ss:// vmess://";
"Kct-KD-qPN.ibShadowedToolTip" = "ss:// or vmess://";
/* Class = "NSMenuItem"; title = "Import Server From Pasteboard"; ObjectID = "Kct-KD-qPN"; */
"Kct-KD-qPN.title" = "从粘贴板导入";
"Kct-KD-qPN.title" = "从粘贴板导入服务器";
/* Class = "NSMenu"; title = "Servers"; ObjectID = "NCx-DY-Hm4"; */
"NCx-DY-Hm4.title" = "服务列表";
"NCx-DY-Hm4.title" = "服务列表";
/* Class = "NSMenuItem"; title = "Substitutions"; ObjectID = "Ndr-EN-mCf"; */
"Ndr-EN-mCf.title" = "Substitutions";
@@ -92,9 +95,15 @@
/* Class = "NSMenuItem"; title = "Turn v2ray-core Off"; ObjectID = "SML-EF-rdT"; */
"SML-EF-rdT.title" = "停用v2ray-core";
/* Class = "NSMenuItem"; title = "has new version"; ObjectID = "SdL-DD-qZe"; */
"SdL-DD-qZe.title" = "has new version";
/* Class = "NSMenu"; title = "Substitutions"; ObjectID = "VH3-Bb-D9P"; */
"VH3-Bb-D9P.title" = "Substitutions";
/* Class = "NSMenuItem"; title = "Routing"; ObjectID = "VNg-as-9we"; */
"VNg-as-9we.title" = "路由";
/* Class = "NSMenu"; title = "Edit"; ObjectID = "VmT-t8-f8R"; */
"VmT-t8-f8R.title" = "Edit";
@@ -111,7 +120,7 @@
"YJ7-xF-H1b.title" = "Spelling and Grammar";
/* Class = "NSMenuItem"; title = "Configure..."; ObjectID = "YoX-II-o27"; */
"YoX-II-o27.title" = "服务器设置";
"YoX-II-o27.title" = "服务器设置...";
/* Class = "NSMenuItem"; title = "Start Speaking"; ObjectID = "Z1o-Jx-e0t"; */
"Z1o-Jx-e0t.title" = "Start Speaking";
@@ -125,6 +134,9 @@
/* Class = "NSMenuItem"; title = "Make Upper Case"; ObjectID = "aeo-mB-Ib5"; */
"aeo-mB-Ib5.title" = "Make Upper Case";
/* Class = "NSMenuItem"; title = "View config.json"; ObjectID = "b3o-tG-rp3"; */
"b3o-tG-rp3.title" = "查看config.json";
/* Class = "NSMenuItem"; title = "Servers"; ObjectID = "cio-ej-HL5"; */
"cio-ej-HL5.title" = "服务器列表";
@@ -147,7 +159,7 @@
"hGZ-5v-1Gx.title" = "Find…";
/* Class = "NSMenuItem"; title = "Manual Mode"; ObjectID = "hTu-27-5OL"; */
"hTu-27-5OL.title" = "手动模式";
"hTu-27-5OL.title" = "手动模式(不改变系统代理)";
/* Class = "NSMenuItem"; title = "Help"; ObjectID = "hWR-vJ-0Au"; */
"hWR-vJ-0Au.title" = "帮助";
@@ -188,11 +200,14 @@
/* Class = "NSMenuItem"; title = "Jump to Selection"; ObjectID = "vkH-fu-RjN"; */
"vkH-fu-RjN.title" = "Jump to Selection";
/* Class = "NSMenuItem"; title = "View pac file"; ObjectID = "vvd-2v-T8I"; */
"vvd-2v-T8I.title" = "查看pac文件";
/* Class = "NSMenuItem"; title = "Paste and Match Style"; ObjectID = "wgi-Ri-oTY"; */
"wgi-Ri-oTY.title" = "Paste and Match Style";
/* Class = "NSMenu"; title = "Routing"; ObjectID = "ykF-uD-Nb1"; */
"ykF-uD-Nb1.title" = "路由";
/* Class = "NSMenuItem"; title = "Check Spelling While Typing"; ObjectID = "zAf-Lw-Sh2"; */
"zAf-Lw-Sh2.title" = "Check Spelling While Typing";
/* Class = "NSMenuItem"; title = "View config.json"; ObjectID = "b3o-tG-rp3"; */
"b3o-tG-rp3.title" = "查看config.json";

View File

@@ -5,6 +5,12 @@
/* Class = "NSTextFieldCell"; title = "V2ray Core Log level:"; ObjectID = "Ctq-lX-cuA"; */
"Ctq-lX-cuA.title" = "v2ray-core日志等级:";
/* Class = "NSButtonCell"; title = "Enable sniffing"; ObjectID = "DUz-lv-lyg"; */
"DUz-lv-lyg.title" = "Enable sniffing";
/* Class = "NSTextFieldCell"; title = "Label"; ObjectID = "GyI-8o-VH6"; */
"GyI-8o-VH6.title" = "Label";
/* Class = "NSTextFieldCell"; placeholderString = " 1087"; ObjectID = "U2E-Gk-3e0"; */
"U2E-Gk-3e0.placeholderString" = " 1087";
@@ -20,8 +26,8 @@
/* Class = "NSTextFieldCell"; title = "Mux:"; ObjectID = "aux-FG-ubc"; */
"aux-FG-ubc.title" = "Mux:";
/* Class = "NSTextFieldCell"; title = "Dns:"; ObjectID = "c7W-6e-soa"; */
"c7W-6e-soa.title" = "Dns:";
/* Class = "NSTextFieldCell"; title = "127.0.0.1"; ObjectID = "az8-jb-B7A"; */
"az8-jb-B7A.title" = "127.0.0.1";
/* Class = "NSTextFieldCell"; placeholderString = " 1080"; ObjectID = "cEB-VU-kcL"; */
"cEB-VU-kcL.placeholderString" = " 1080";
@@ -38,14 +44,17 @@
/* Class = "NSMenuItem"; title = "none"; ObjectID = "hwH-DG-b6w"; */
"hwH-DG-b6w.title" = "none";
/* Class = "NSTextFieldCell"; title = "Local Sock Listen Host:"; ObjectID = "jwm-cF-Zeb"; */
"jwm-cF-Zeb.title" = "本机Sock监听地址:";
/* Class = "NSButtonCell"; title = "Enable Mux"; ObjectID = "k2J-Q7-yOi"; */
"k2J-Q7-yOi.title" = "启用Mux";
/* Class = "NSMenuItem"; title = "info"; ObjectID = "kHt-j0-6zV"; */
"kHt-j0-6zV.title" = "info";
/* Class = "NSTextFieldCell"; title = "8.8.8.8,1.1.1.1,114.114.114.114,119.29.29.29"; ObjectID = "lKP-40-S8o"; */
"lKP-40-S8o.title" = "8.8.8.8,1.1.1.1,114.114.114.114,119.29.29.29";
/* Class = "NSTextFieldCell"; title = "127.0.0.1"; ObjectID = "os8-UE-0fP"; */
"os8-UE-0fP.title" = "127.0.0.1";
/* Class = "NSMenuItem"; title = "debug"; ObjectID = "qDP-Eo-IWC"; */
"qDP-Eo-IWC.title" = "debug";
@@ -53,17 +62,11 @@
/* Class = "NSBox"; title = "Local"; ObjectID = "tMz-nM-arv"; */
"tMz-nM-arv.title" = "本机";
/* Class = "NSTextFieldCell"; title = "Local Http Listen Host:"; ObjectID = "uWf-ty-nD8"; */
"uWf-ty-nD8.title" = "本机Http监听地址:";
/* Class = "NSTextFieldCell"; title = "Pac Server Listen Port:"; ObjectID = "you-iw-OS5"; */
"you-iw-OS5.title" = "Pac监听端口:";
/* Class = "NSMenuItem"; title = "warning"; ObjectID = "z4S-wG-fyc"; */
"z4S-wG-fyc.title" = "warning";
/* Class = "NSTextFieldCell"; title = "Local Sock Listen Host:"; ObjectID = "jwm-cF-Zeb"; */
"jwm-cF-Zeb.title" = "本机Sock监听Host:";
/* Class = "NSTextFieldCell"; title = "Local Http Listen Host:"; ObjectID = "uWf-ty-nD8"; */
"uWf-ty-nD8.title" = "本机http监听Host:";
/* Class = "NSButtonCell"; title = "Enable sniffing"; ObjectID = "DUz-lv-lyg"; */
"DUz-lv-lyg.title" = "开启流量探测";

View File

@@ -1,34 +1,30 @@
/* Class = "NSButtonCell"; title = "show logs"; ObjectID = "0fD-xL-Tly"; */
"0fD-xL-Tly.title" = "显示日志";
/* Class = "NSTextFieldCell"; title = "Toggle V2ray On/Off:"; ObjectID = "0rn-re-Wn3"; */
"0rn-re-Wn3.title" = "启停 V2ray:";
/* Class = "NSButtonCell"; title = "Automatically update servers from subscriptions "; ObjectID = "1FR-Yu-tqb"; */
"1FR-Yu-tqb.title" = "自动更新订阅列表(启动和唤醒时)";
/* Class = "NSButtonCell"; title = "Check for Updates..."; ObjectID = "2p9-GL-XZ9"; */
"2p9-GL-XZ9.title" = "检查更新";
/* Class = "NSButtonCell"; title = "clear logs"; ObjectID = "2vr-uU-fMI"; */
"2vr-uU-fMI.title" = "清除日志";
/* Class = "NSTextFieldCell"; title = "Switch Proxy Mode:"; ObjectID = "Eu4-bo-oYs"; */
"Eu4-bo-oYs.title" = "切换代理模式:";
/* Class = "NSButtonCell"; title = "Launch V2rayU at login"; ObjectID = "NZE-cI-j04"; */
"NZE-cI-j04.title" = "开机自动启动";
/* Class = "NSButtonCell"; title = "Feedback..."; ObjectID = "QjX-NH-23u"; */
"QjX-NH-23u.title" = "问题反馈...";
/* Class = "NSButtonCell"; title = "Clear Logs Everyday Automutically"; ObjectID = "hIN-yp-Qul"; */
"hIN-yp-Qul.title" = "每次启动自动清除日志";
/* Class = "NSButtonCell"; title = "Check for Updates automutically"; ObjectID = "m2S-Mu-rFM"; */
"m2S-Mu-rFM.title" = "自动检测版本更新";
/* Class = "NSTextFieldCell"; title = "Related file locations:"; ObjectID = "Oke-cL-DfS"; */
"Oke-cL-DfS.title" = "相关文件路径:";
/* Class = "NSTextFieldCell"; title = "Switch Proxy Mode:"; ObjectID = "Eu4-bo-oYs"; */
"Eu4-bo-oYs.title" = "切换代理模式:";
/* Class = "NSButtonCell"; title = "Feedback..."; ObjectID = "QjX-NH-23u"; */
"QjX-NH-23u.title" = "问题反馈...";
/* Class = "NSTextFieldCell"; title = "Toggle V2ray On/Off:"; ObjectID = "0rn-re-Wn3"; */
"0rn-re-Wn3.title" = "打开关闭代理:";
/* Class = "NSButtonCell"; title = "Automatically update servers from subscriptions"; ObjectID = "1FR-Yu-tqb"; */
"1FR-Yu-tqb.title" = "启动或唤醒时自动从订阅中更新";
/* Class = "NSButtonCell"; title = "Automatically select fastest server"; ObjectID = "WsS-I0-2Zs"; */
"WsS-I0-2Zs.title" = "连接失败后选择最快server重连";
"WsS-I0-2Zs.title" = "自动选择最快的服务器";
/* Class = "NSButtonCell"; title = "Check for updates automutically"; ObjectID = "m2S-Mu-rFM"; */
"m2S-Mu-rFM.title" = "自动检查版本更新";
/* Class = "NSTextFieldCell"; title = "~/.V2rayU/\n~/Library/Preferences/net.yanue.V2rayU.plist"; ObjectID = "vHZ-BS-uFb"; */
"vHZ-BS-uFb.title" = "~/.V2rayU/\n~/Library/Preferences/net.yanue.V2rayU.plist";