misc: add setting interface

This commit is contained in:
yicheng 2022-11-20 12:08:46 +08:00
parent 2b37be74ec
commit 3c86163008
16 changed files with 373 additions and 87 deletions

View File

@ -39,6 +39,8 @@
4982F51F2344A216008804B0 /* Cgo+Convert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4982F51E2344A216008804B0 /* Cgo+Convert.swift */; };
49862FA0218418C600A1D5EC /* ClashRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49862F9F218418C600A1D5EC /* ClashRule.swift */; };
4989F98E20D0AE990001E564 /* sampleConfig.yaml in Resources */ = {isa = PBXBuildFile; fileRef = 4989F98D20D0AE990001E564 /* sampleConfig.yaml */; };
498BC2532929CC2A00CA8084 /* SettingTabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 498BC2522929CC2A00CA8084 /* SettingTabViewController.swift */; };
498BC2552929CCAE00CA8084 /* GeneralSettingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 498BC2542929CCAE00CA8084 /* GeneralSettingViewController.swift */; };
499976C821359F0400E7BF83 /* ClashWebViewContoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = 499976C721359F0400E7BF83 /* ClashWebViewContoller.swift */; };
499A485522ED707300F6C675 /* RemoteConfigViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 499A485322ED707300F6C675 /* RemoteConfigViewController.swift */; };
499A485822ED715200F6C675 /* RemoteConfigModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 499A485722ED715200F6C675 /* RemoteConfigModel.swift */; };
@ -162,6 +164,8 @@
49862F9F218418C600A1D5EC /* ClashRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClashRule.swift; sourceTree = "<group>"; };
498960722340F21C00AFB7EC /* com.west2online.ClashX.ProxyConfigHelper.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = com.west2online.ClashX.ProxyConfigHelper.entitlements; sourceTree = "<group>"; };
4989F98D20D0AE990001E564 /* sampleConfig.yaml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.yaml; path = sampleConfig.yaml; sourceTree = "<group>"; };
498BC2522929CC2A00CA8084 /* SettingTabViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingTabViewController.swift; sourceTree = "<group>"; };
498BC2542929CCAE00CA8084 /* GeneralSettingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralSettingViewController.swift; sourceTree = "<group>"; };
499976C721359F0400E7BF83 /* ClashWebViewContoller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClashWebViewContoller.swift; sourceTree = "<group>"; };
499A485322ED707300F6C675 /* RemoteConfigViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteConfigViewController.swift; sourceTree = "<group>"; };
499A485722ED715200F6C675 /* RemoteConfigModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteConfigModel.swift; sourceTree = "<group>"; };
@ -385,6 +389,7 @@
4989F98520D0AA300001E564 /* ViewControllers */ = {
isa = PBXGroup;
children = (
498BC2512929CC0A00CA8084 /* Settings */,
49BC061B212931F4005A0FE7 /* AboutViewController.swift */,
499976C721359F0400E7BF83 /* ClashWebViewContoller.swift */,
499A485322ED707300F6C675 /* RemoteConfigViewController.swift */,
@ -393,6 +398,15 @@
path = ViewControllers;
sourceTree = "<group>";
};
498BC2512929CC0A00CA8084 /* Settings */ = {
isa = PBXGroup;
children = (
498BC2522929CC2A00CA8084 /* SettingTabViewController.swift */,
498BC2542929CCAE00CA8084 /* GeneralSettingViewController.swift */,
);
path = Settings;
sourceTree = "<group>";
};
4997732220D251A60009B136 /* Basic */ = {
isa = PBXGroup;
children = (
@ -721,6 +735,7 @@
49D176A72355FE680093DD7B /* NetworkChangeNotifier.swift in Sources */,
4913C82321157D0200F6B87C /* Notification.swift in Sources */,
8ACD21BD27A04ED500BC4632 /* ProxyModeChangeCommand.swift in Sources */,
498BC2552929CCAE00CA8084 /* GeneralSettingViewController.swift in Sources */,
49228457270AADE20027A4B6 /* RemoteConfigUpdateIntervalSettingView.swift in Sources */,
F9203A26236342820020D57D /* AppDelegate+..swift in Sources */,
499A485C22ED793C00F6C675 /* NSView+Nib.swift in Sources */,
@ -760,6 +775,7 @@
493AEAE5221AE7230016FE98 /* ProxyMenuItem.swift in Sources */,
499A485E22ED9B7C00F6C675 /* NSTableView+Reload.swift in Sources */,
F939724C23A4B33500FE5A3F /* ClashProvider.swift in Sources */,
498BC2532929CC2A00CA8084 /* SettingTabViewController.swift in Sources */,
49862FA0218418C600A1D5EC /* ClashRule.swift in Sources */,
49C9EF64223E78F5005D8B6A /* ClashProxy.swift in Sources */,
4929F684258CE07500A435F6 /* UserDefaultWrapper.swift in Sources */,

View File

@ -490,7 +490,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
if WebPortalManager.hasWebProtal {
WebPortalManager.shared.addWebProtalMenuItem(&statusMenu)
}
ICloudManager.shared.addEnableMenuItem(&experimentalMenu)
AutoUpgardeManager.shared.setup()
AutoUpgardeManager.shared.addChanelMenuItem(&experimentalMenu)
updateExperimentalFeatureStatus()
@ -695,7 +694,7 @@ extension AppDelegate {
extension AppDelegate {
@IBAction func openConfigFolder(_ sender: Any) {
if ICloudManager.shared.isICloudEnable() {
if ICloudManager.shared.useiCloud.value {
ICloudManager.shared.getUrl {
url in
if let url = url {
@ -841,7 +840,7 @@ extension AppDelegate {
}
}
if ICloudManager.shared.isICloudEnable() {
if ICloudManager.shared.useiCloud.value {
ICloudManager.shared.getConfigFilesList { list in
action(list)
}

View File

@ -1,11 +1,198 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="19162" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="21507" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="19162"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21507"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Settings-->
<scene sceneID="7zJ-aQ-tNg">
<objects>
<tabViewController title="Settings" showSeguePresentationStyle="single" selectedTabViewItemIndex="0" id="LAj-p8-9gd" customClass="SettingTabViewController" customModule="ClashX_Pro" customModuleProvider="target" sceneMemberID="viewController">
<tabViewItems>
<tabViewItem label="General" identifier="general" image="gearshape" catalog="system" id="Ltt-Vq-Hh1"/>
</tabViewItems>
<tabView key="tabView" type="noTabsNoBorder" id="81C-Yt-rOb">
<rect key="frame" x="0.0" y="0.0" width="379" height="300"/>
<autoresizingMask key="autoresizingMask"/>
<font key="font" metaFont="message"/>
<connections>
<outlet property="delegate" destination="LAj-p8-9gd" id="1gb-Jv-3mL"/>
</connections>
</tabView>
<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"/>
</connections>
</tabViewController>
<customObject id="bpW-G9-2N4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="980.5" y="1074"/>
</scene>
<!--General-->
<scene sceneID="XxM-Ti-kkw">
<objects>
<viewController title="General" showSeguePresentationStyle="single" id="kma-mp-ncL" customClass="GeneralSettingViewController" customModule="ClashX_Pro" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" misplaced="YES" id="dpe-v8-fF7">
<rect key="frame" x="0.0" y="0.0" width="400" height="299"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView distribution="fill" orientation="vertical" alignment="leading" spacing="10" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="VYa-DX-JOe">
<rect key="frame" x="20" y="20" width="340" height="273"/>
<subviews>
<box borderType="line" title="Box" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="Gnh-m8-PAz">
<rect key="frame" x="-3" y="179" width="346" height="96"/>
<view key="contentView" id="Lai-8r-q7z">
<rect key="frame" x="4" y="5" width="338" height="88"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView distribution="fill" orientation="vertical" alignment="leading" spacing="10" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="j6Y-mY-tCG">
<rect key="frame" x="20" y="10" width="211" height="68"/>
<subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="jsq-3u-CRd">
<rect key="frame" x="-2" y="51" width="119" height="18"/>
<buttonCell key="cell" type="check" title="Launch at login" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="dV6-4Z-2SO">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="UGu-wD-xUs">
<rect key="frame" x="-2" y="25" width="213" height="18"/>
<buttonCell key="cell" type="check" title="Use iCloud to store config files" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="p7q-KN-kIv">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="6V3-wn-WSa">
<rect key="frame" x="-2" y="-1" width="150" height="18"/>
<buttonCell key="cell" type="check" title="Reduce notifications" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="jsL-HC-6ne">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
</subviews>
<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="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"/>
</constraints>
</view>
</box>
<box borderType="line" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="hnq-VC-kO5">
<rect key="frame" x="-3" y="-4" width="346" height="179"/>
<view key="contentView" id="Xgo-Uz-aYp">
<rect key="frame" x="4" y="5" width="338" height="171"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView borderType="none" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Drl-od-EZH">
<rect key="frame" x="20" y="20" width="298" height="100"/>
<clipView key="contentView" drawsBackground="NO" id="twj-rO-KRO">
<rect key="frame" x="0.0" y="0.0" width="298" height="100"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textView wantsLayer="YES" importsGraphics="NO" richText="NO" verticallyResizable="YES" spellingCorrection="YES" smartInsertDelete="YES" id="CkT-hn-ntr">
<rect key="frame" x="0.0" y="0.0" width="298" height="100"/>
<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="298" height="100"/>
<size key="maxSize" width="338" height="10000000"/>
<color key="insertionPointColor" name="textColor" catalog="System" colorSpace="catalog"/>
</textView>
</subviews>
</clipView>
<constraints>
<constraint firstAttribute="height" constant="100" id="5hr-fq-T9B"/>
</constraints>
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="O4Z-0A-dqb">
<rect key="frame" x="-100" y="-100" width="240" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="NhZ-Ru-Rz5">
<rect key="frame" x="282" y="0.0" width="16" height="100"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="TVZ-xJ-zK0">
<rect key="frame" x="18" y="145" width="302" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Bypass proxy settings for there Hosts &amp; Domains" id="NPu-V9-f3r">
<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="VvP-5I-QhW">
<rect key="frame" x="18" y="128" width="302" height="13"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Separated by commas(,)" id="sfe-wu-UXp">
<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>
</subviews>
<constraints>
<constraint firstItem="VvP-5I-QhW" firstAttribute="top" secondItem="TVZ-xJ-zK0" secondAttribute="bottom" constant="4" id="1po-0W-bad"/>
<constraint firstItem="VvP-5I-QhW" firstAttribute="leading" secondItem="Xgo-Uz-aYp" secondAttribute="leading" constant="20" symbolic="YES" id="2fv-Fh-IS5"/>
<constraint firstItem="TVZ-xJ-zK0" firstAttribute="top" secondItem="Xgo-Uz-aYp" secondAttribute="top" constant="10" id="6Oi-bz-JJP"/>
<constraint firstItem="TVZ-xJ-zK0" firstAttribute="leading" secondItem="Xgo-Uz-aYp" secondAttribute="leading" constant="20" symbolic="YES" id="7BO-WX-UxM"/>
<constraint firstAttribute="trailing" secondItem="TVZ-xJ-zK0" secondAttribute="trailing" constant="20" symbolic="YES" id="7cE-3w-m7O"/>
<constraint firstItem="Drl-od-EZH" firstAttribute="top" secondItem="VvP-5I-QhW" secondAttribute="bottom" constant="8" symbolic="YES" id="9yR-yV-D8N"/>
<constraint firstAttribute="bottom" secondItem="Drl-od-EZH" secondAttribute="bottom" constant="20" symbolic="YES" id="AcE-tj-Dez"/>
<constraint firstItem="Drl-od-EZH" firstAttribute="leading" secondItem="Xgo-Uz-aYp" secondAttribute="leading" constant="20" symbolic="YES" id="Ksd-gK-GZk"/>
<constraint firstAttribute="trailing" secondItem="Drl-od-EZH" secondAttribute="trailing" constant="20" symbolic="YES" id="Vje-ww-unT"/>
<constraint firstAttribute="trailing" secondItem="VvP-5I-QhW" secondAttribute="trailing" constant="20" symbolic="YES" id="qN5-ZB-oNC"/>
</constraints>
</view>
<constraints>
<constraint firstAttribute="width" constant="340" id="fZn-M3-rRD"/>
</constraints>
</box>
</subviews>
<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="Ogn-LZ-PV6"/>
</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 firstItem="VYa-DX-JOe" firstAttribute="top" secondItem="dpe-v8-fF7" secondAttribute="top" constant="10" id="EUx-BN-eD8"/>
<constraint firstAttribute="trailing" secondItem="VYa-DX-JOe" secondAttribute="trailing" constant="20" symbolic="YES" id="o5S-vk-NgG"/>
<constraint firstItem="VYa-DX-JOe" firstAttribute="leading" secondItem="dpe-v8-fF7" secondAttribute="leading" constant="20" symbolic="YES" id="s6F-zq-Aoy"/>
<constraint firstAttribute="bottom" secondItem="VYa-DX-JOe" secondAttribute="bottom" constant="20" symbolic="YES" id="yn9-zb-pHs"/>
</constraints>
</view>
<connections>
<outlet property="ignoreListTextView" destination="CkT-hn-ntr" id="Rhb-jw-9wz"/>
<outlet property="launchAtLoginButton" destination="jsq-3u-CRd" id="RnH-Va-nCX"/>
<outlet property="reduceNotificationsButton" destination="6V3-wn-WSa" id="VtV-aI-dQi"/>
<outlet property="useiCloudButton" destination="UGu-wD-xUs" id="VSD-og-kEv"/>
</connections>
</viewController>
<customObject id="Co2-xv-pHW" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1546" y="1029.5"/>
</scene>
<!--Application-->
<scene sceneID="JPo-4y-FX3">
<objects>
@ -290,6 +477,13 @@
<action selector="actionUpdateConfig:" target="Voe-Tx-rLC" id="oW5-Ll-SY8"/>
</connections>
</menuItem>
<menuItem title="Settings" id="krh-QF-pqZ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="actionUpdateConfig:" target="Voe-Tx-rLC" id="L8c-KG-g8D"/>
<segue destination="LAj-p8-9gd" kind="show" id="BTv-JW-0Fb"/>
</connections>
</menuItem>
<menuItem title="Remote config" id="h1C-R6-Y9w">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Remote config" id="az2-wz-yyy">
@ -677,7 +871,7 @@
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="urlCell" id="Nfz-jY-8Of">
<rect key="frame" x="11" y="1" width="181" height="30"/>
<rect key="frame" x="1" y="1" width="181" height="30"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="4q7-nk-ts1">
@ -716,7 +910,7 @@
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="nameCell" id="nJ2-CL-UMO">
<rect key="frame" x="195" y="1" width="86" height="17"/>
<rect key="frame" x="185" y="1" width="86" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="ma1-VU-D1q">
@ -755,7 +949,7 @@
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="timeCell" id="EV1-my-fwa">
<rect key="frame" x="284" y="1" width="56" height="17"/>
<rect key="frame" x="274" y="1" width="56" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="giF-oe-BsQ">
@ -912,7 +1106,7 @@
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="nameCell" id="8mR-Pw-M5O">
<rect key="frame" x="11" y="1" width="193" height="28"/>
<rect key="frame" x="1" y="1" width="193" height="28"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="6q3-XW-4SC">
@ -957,7 +1151,7 @@
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="urlCell" id="hgu-Ez-7fj">
<rect key="frame" x="207" y="1" width="188" height="28"/>
<rect key="frame" x="197" y="1" width="188" height="28"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="rfv-RN-Pkz">
@ -999,7 +1193,7 @@
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="secretCell" id="1lj-rr-UvU">
<rect key="frame" x="398" y="1" width="54" height="22"/>
<rect key="frame" x="388" y="1" width="54" height="22"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="T9c-i1-UF2">
@ -1122,5 +1316,6 @@
</scenes>
<resources>
<image name="AppIcon" width="128" height="128"/>
<image name="gearshape" catalog="system" width="16" height="16"/>
</resources>
</document>

View File

@ -105,7 +105,7 @@ class ApiRequest {
}
static func requestConfigUpdate(configName: String, callback: @escaping ((ErrorString?) -> Void)) {
if ICloudManager.shared.isICloudEnable() {
if ICloudManager.shared.useiCloud.value {
ICloudManager.shared.getUrl { url in
guard let url = url else {
callback("icloud error")

View File

@ -55,7 +55,7 @@ class ConfigManager {
}
static func watchCurrentConfigFile() {
if ICloudManager.shared.isICloudEnable() {
if ICloudManager.shared.useiCloud.value {
ICloudManager.shared.getUrl { url in
guard let url = url else { return }
let configUrl = url.appendingPathComponent(Paths.configFileName(for: selectConfigName))

View File

@ -7,6 +7,8 @@
//
import Cocoa
import RxSwift
import RxCocoa
class ICloudManager {
static let shared = ICloudManager()
@ -14,23 +16,28 @@ class ICloudManager {
private var metaQuery: NSMetadataQuery?
private var enableMenuItem: NSMenuItem?
private var icloudAvailable = false {
didSet { updateMenuItemStatus() }
didSet { useiCloud.accept(userEnableiCloud && icloudAvailable) }
}
private var disposeBag = DisposeBag()
private var userEnableiCloud: Bool = UserDefaults.standard.bool(forKey: "kUserEnableiCloud") {
didSet { UserDefaults.standard.set(userEnableiCloud, forKey: "kUserEnableiCloud") }
let useiCloud = BehaviorRelay<Bool>(value: false)
var userEnableiCloud: Bool = UserDefaults.standard.bool(forKey: "kUserEnableiCloud") {
didSet {
UserDefaults.standard.set(userEnableiCloud, forKey: "kUserEnableiCloud")
useiCloud.accept(userEnableiCloud && icloudAvailable)
}
}
func setup() {
addNotification()
icloudAvailable = isICloudAvailable()
if isICloudEnable() {
checkiCloud()
}
}
useiCloud.distinctUntilChanged().filter({$0}).subscribe {
[weak self] _ in
self?.checkiCloud()
}.disposed(by: disposeBag)
func isICloudEnable() -> Bool {
return icloudAvailable && userEnableiCloud
icloudAvailable = isICloudAvailable()
useiCloud.accept(userEnableiCloud && icloudAvailable)
}
func getConfigFilesList(configs: @escaping (([String]) -> Void)) {
@ -48,19 +55,16 @@ class ICloudManager {
}
private func checkiCloud() {
if isICloudAvailable() {
icloudAvailable = true
getUrl { url in
guard let url = url else {
self.icloudAvailable = false
return
}
let files = try? FileManager.default.contentsOfDirectory(atPath: url.path)
if let count = files?.count, count == 0 {
let path = Bundle.main.path(forResource: "sampleConfig", ofType: "yaml")!
try? FileManager.default.copyItem(atPath: path, toPath: kDefaultConfigFilePath)
try? FileManager.default.copyItem(atPath: Bundle.main.path(forResource: "sampleConfig", ofType: "yaml")!, toPath: url.appendingPathComponent("config.yaml").path)
}
getUrl { url in
guard let url = url else {
self.icloudAvailable = false
return
}
let files = try? FileManager.default.contentsOfDirectory(atPath: url.path)
if let count = files?.count, count == 0 {
let path = Bundle.main.path(forResource: "sampleConfig", ofType: "yaml")!
try? FileManager.default.copyItem(atPath: path, toPath: kDefaultConfigFilePath)
try? FileManager.default.copyItem(atPath: Bundle.main.path(forResource: "sampleConfig", ofType: "yaml")!, toPath: url.appendingPathComponent("config.yaml").path)
}
}
}
@ -103,23 +107,3 @@ class ICloudManager {
icloudAvailable = isICloudAvailable()
}
}
extension ICloudManager {
func addEnableMenuItem(_ menu: inout NSMenu) {
let item = NSMenuItem(title: NSLocalizedString("Use iCloud", comment: ""), action: #selector(enableMenuItemTap(sender:)), keyEquivalent: "")
menu.addItem(item)
enableMenuItem = item
updateMenuItemStatus()
}
@objc func enableMenuItemTap(sender: NSMenuItem) {
userEnableiCloud = !userEnableiCloud
updateMenuItemStatus()
checkiCloud()
}
func updateMenuItemStatus() {
enableMenuItem?.state = isICloudEnable() ? .on : .off
enableMenuItem?.target = icloudAvailable ? self : nil
}
}

View File

@ -83,7 +83,7 @@ class MenuItemFactory {
return
}
if ICloudManager.shared.isICloudEnable() {
if ICloudManager.shared.useiCloud.value {
ICloudManager.shared.getConfigFilesList {
complete($0.map { generateMenuItem($0) })
}

View File

@ -173,7 +173,7 @@ class RemoteConfigManager {
}
config.isPlaceHolderName = false
if ICloudManager.shared.isICloudEnable() {
if ICloudManager.shared.useiCloud.value {
ConfigFileManager.shared.stopWatchConfigFile()
} else if config.name == ConfigManager.selectConfigName {
ConfigFileManager.shared.pauseForNextChange()
@ -192,7 +192,7 @@ class RemoteConfigManager {
}
}
if ICloudManager.shared.isICloudEnable() {
if ICloudManager.shared.useiCloud.value {
ICloudManager.shared.getUrl { url in
guard let url = url else { return }
let saveUrl = url.appendingPathComponent(Paths.configFileName(for: config.name))

View File

@ -29,6 +29,8 @@ enum Settings {
"127.0.0.1",
"localhost",
"*.local",
"timestamp.apple.com"])
"timestamp.apple.com",
"sequoia.apple.com",
"seed-sequoia.siri.apple.com"])
static var proxyIgnoreList: [String]
}

View File

@ -64,6 +64,9 @@
/* No comment provided by engineer. */
"Fail:" = "Fail:";
/* No comment provided by engineer. */
"fails: %@" = "fails: %@";
/* No comment provided by engineer. */
"Global" = "Global";
@ -108,6 +111,9 @@
/* No comment provided by engineer. */
"Quit" = "Quit";
/* No comment provided by engineer. */
"Reduce alerts if notification permission is disabled" = "Reduce alerts if notification permission is disabled";
/* No comment provided by engineer. */
"Reload Config Fail" = "Reload Config Fail";

View File

@ -64,6 +64,9 @@
/* No comment provided by engineer. */
"Fail:" = "失败:";
/* No comment provided by engineer. */
"fails: %@" = "失败: %@";
/* No comment provided by engineer. */
"Global" = "全局";
@ -108,6 +111,9 @@
/* No comment provided by engineer. */
"Quit" = "退出";
/* No comment provided by engineer. */
"Reduce alerts if notification permission is disabled" = "在通知权限关闭时减少提示弹窗";
/* No comment provided by engineer. */
"Reload Config Fail" = "重载配置文件失败";

View File

@ -0,0 +1,53 @@
//
// GeneralSettingViewController.swift
// ClashX Pro
//
// Created by yicheng on 2022/11/20.
// Copyright © 2022 west2online. All rights reserved.
//
import Cocoa
import RxSwift
class GeneralSettingViewController: NSViewController {
@IBOutlet var ignoreListTextView: NSTextView!
@IBOutlet weak var launchAtLoginButton: NSButton!
@IBOutlet weak var reduceNotificationsButton: NSButton!
@IBOutlet weak var useiCloudButton: NSButton!
var disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
ignoreListTextView.string = Settings.proxyIgnoreList.joined(separator: ",")
ignoreListTextView.rx
.string.debounce(.milliseconds(500), scheduler: MainScheduler.instance)
.map { $0.components(separatedBy: ",").filter {!$0.isEmpty} }
.subscribe { arr in
print(arr)
Settings.proxyIgnoreList = arr
}.disposed(by: disposeBag)
LaunchAtLogin.shared.isEnableVirable
.map { $0 ? .on : .off }
.bind(to: launchAtLoginButton.rx.state)
.disposed(by: disposeBag)
launchAtLoginButton.rx.state.map({$0 == .on}).subscribe {
LaunchAtLogin.shared.isEnabled = $0
}.disposed(by: disposeBag)
ICloudManager.shared.useiCloud
.map { $0 ? .on : .off }
.bind(to: useiCloudButton.rx.state)
.disposed(by: disposeBag)
useiCloudButton.rx.state.map({$0 == .on}).subscribe {
ICloudManager.shared.userEnableiCloud = $0
}.disposed(by: disposeBag)
reduceNotificationsButton.toolTip = NSLocalizedString("Reduce alerts if notification permission is disabled", comment: "")
reduceNotificationsButton.state = Settings.disableNoti ? .on : .off
reduceNotificationsButton.rx.state.map {$0 == .on }.subscribe {
Settings.disableNoti = $0
}.disposed(by: disposeBag)
}
}

View File

@ -0,0 +1,19 @@
//
// SettingTabViewController.swift
// ClashX Pro
//
// Created by yicheng on 2022/11/20.
// Copyright © 2022 west2online. All rights reserved.
//
import Cocoa
class SettingTabViewController: NSTabViewController {
override func viewDidLoad() {
super.viewDidLoad()
tabStyle = .toolbar
NSApp.activate(ignoringOtherApps: true)
}
}

View File

@ -190,5 +190,35 @@
/* Class = "NSTextFieldCell"; title = "This allows you to control the clash core running in the different machine"; ObjectID = "WkL-aX-66E"; */
"WkL-aX-66E.title" = "远程控制器允许你控制其他设备上的 Clash 状态。";
/* Class = "NSMenuItem"; title = "Set update Interval"; ObjectID = "h1H-7k-9HS"; */
/* Class = "NSMenuItem"; title = "Set update interval"; ObjectID = "h1H-7k-9HS"; */
"h1H-7k-9HS.title" = "设置更新间隔";
/* Class = "NSBox"; title = "Box"; ObjectID = "Gnh-m8-PAz"; */
"Gnh-m8-PAz.title" = "";
/* Class = "NSTabViewController"; title = "Settings"; ObjectID = "LAj-p8-9gd"; */
"LAj-p8-9gd.title" = "ClashX 设置";
/* Class = "NSTabViewItem"; label = "General"; ObjectID = "Ltt-Vq-Hh1"; */
"Ltt-Vq-Hh1.label" = "通用";
/* Class = "NSTextFieldCell"; title = "Bypass proxy settings for there Hosts & Domains"; ObjectID = "NPu-V9-f3r"; */
"NPu-V9-f3r.title" = "忽略这些主机与域的代理设置";
/* Class = "NSButtonCell"; title = "Launch at login"; ObjectID = "dV6-4Z-2SO"; */
"dV6-4Z-2SO.title" = "开机启动";
/* Class = "NSViewController"; title = "General"; ObjectID = "kma-mp-ncL"; */
"kma-mp-ncL.title" = "";
/* Class = "NSMenuItem"; title = "Settings"; ObjectID = "krh-QF-pqZ"; */
"krh-QF-pqZ.title" = "更多设置";
/* Class = "NSButtonCell"; title = "Use iCloud to store config files"; ObjectID = "p7q-KN-kIv"; */
"p7q-KN-kIv.title" = "将配置文件存储在iCloud中";
/* Class = "NSButtonCell"; title = "Reduce notifications"; ObjectID = "jsL-HC-6ne"; */
"jsL-HC-6ne.title" = "减少通知";
/* Class = "NSTextFieldCell"; title = "Separated by commas(,)"; ObjectID = "sfe-wu-UXp"; */
"sfe-wu-UXp.title" = "使用英文逗号(,)分隔";

View File

@ -65,13 +65,7 @@ Checkout [Clash](https://github.com/Dreamacro/clash) or [SS-Rule-Snippet for Cla
### Change default system ignore list.
- Download sample plist in the [Here](proxyIgnoreList.plist) and place in the
```
~/.config/clash/proxyIgnoreList.plist
```
- Edit the `proxyIgnoreList.plist` to set up your own proxy ignore list
- Change by menu -> Config -> Setting -> Bypass proxy settings for there Hosts & Domains
### URL Schemes.
@ -106,11 +100,7 @@ script:
### 关闭ClashX的通知
1. 在系统设置中关闭 clashx 的推送权限
2. 执行
```
defaults write com.west2online.ClashX disableNoti -bool true
defaults write com.west2online.ClashXPro disableNoti -bool true
```
2. 在菜单栏->配置->更多设置中选中减少通知
Note强烈不推荐这么做这可能导致clashx的很多重要错误提醒无法显示。

View File

@ -1,14 +0,0 @@
<?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">
<array>
<string>192.168.0.0/16</string>
<string>10.0.0.0/8</string>
<string>172.16.0.0/12</string>
<string>127.0.0.1</string>
<string>localhost</string>
<string>*.local</string>
<string>*.crashlytics.com</string>
<string>my-custom-site.com</string>
</array>
</plist>