Merge branch 'pr/159' into develop
# Conflicts: # ShadowsocksX-NG/Base.lproj/MainMenu.xib
This commit is contained in:
@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
import Carbon
|
||||
|
||||
@NSApplicationMain
|
||||
class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDelegate {
|
||||
@ -18,7 +18,11 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
|
||||
var proxyPreferencesWinCtrl: ProxyPreferencesController!
|
||||
var editUserRulesWinCtrl: UserRulesController!
|
||||
var httpPreferencesWinCtrl : HTTPPreferencesWindowController!
|
||||
|
||||
|
||||
let keyCode = kVK_ANSI_P
|
||||
let modifierKeys = cmdKey+controlKey
|
||||
var hotKeyRef: EventHotKeyRef?
|
||||
|
||||
var launchAtLoginController: LaunchAtLoginController = LaunchAtLoginController()
|
||||
|
||||
@IBOutlet weak var window: NSWindow!
|
||||
@ -41,7 +45,23 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
|
||||
@IBOutlet var serversPreferencesMenuItem: NSMenuItem!
|
||||
|
||||
@IBOutlet weak var lanchAtLoginMenuItem: NSMenuItem!
|
||||
|
||||
|
||||
@IBOutlet weak var hudWindow: NSPanel!
|
||||
@IBOutlet weak var panelView: NSView!
|
||||
@IBOutlet weak var isNameTextField: NSTextField!
|
||||
|
||||
let kHudFadeInDuration: Double = 0.25
|
||||
let kHudFadeOutDuration: Double = 0.5
|
||||
let kHudDisplayDuration: Double = 2.0
|
||||
|
||||
let kHudAlphaValue: CGFloat = 0.75
|
||||
let kHudCornerRadius: CGFloat = 18.0
|
||||
let kHudHorizontalMargin: CGFloat = 30
|
||||
let kHudHeight: CGFloat = 90.0
|
||||
|
||||
var timerToFadeOut: Timer? = nil
|
||||
var fadingOut: Bool = false
|
||||
|
||||
var statusItem: NSStatusItem!
|
||||
|
||||
static let StatusItemIconWidth:CGFloat = 20
|
||||
@ -137,8 +157,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
|
||||
userNote.subtitle = "By Handle SS URL".localized
|
||||
}
|
||||
userNote.informativeText = "Host: \(profile.serverHost)"
|
||||
" Port: \(profile.serverPort)"
|
||||
" Encription Method: \(profile.method)".localized
|
||||
//" Port: \(profile.serverPort)"
|
||||
//" Encription Method: \(profile.method)".localized
|
||||
userNote.soundName = NSUserNotificationDefaultSoundName
|
||||
|
||||
NSUserNotificationCenter.default
|
||||
@ -167,6 +187,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
|
||||
ProxyConfHelper.startMonitorPAC()
|
||||
applyConfig()
|
||||
SyncSSLocal()
|
||||
|
||||
// Register global hotkey
|
||||
registerHotkey()
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ aNotification: Notification) {
|
||||
@ -174,8 +197,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
|
||||
StopSSLocal()
|
||||
StopPrivoxy()
|
||||
ProxyConfHelper.disableProxy()
|
||||
if let ref = hotKeyRef { UnregisterEventHotKey(ref) }
|
||||
}
|
||||
|
||||
|
||||
func applyConfig() {
|
||||
let defaults = UserDefaults.standard
|
||||
let isOn = defaults.bool(forKey: "ShadowsocksOn")
|
||||
@ -197,7 +221,64 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
|
||||
ProxyConfHelper.disableProxy()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Hotkey Methods
|
||||
func registerHotkey() -> Void {
|
||||
var gMyHotKeyID = EventHotKeyID()
|
||||
gMyHotKeyID.signature = OSType(fourCharCodeFrom(string: "sxng"))
|
||||
gMyHotKeyID.id = UInt32(keyCode)
|
||||
|
||||
var eventType = EventTypeSpec()
|
||||
eventType.eventClass = OSType(kEventClassKeyboard)
|
||||
eventType.eventKind = OSType(kEventHotKeyPressed)
|
||||
|
||||
// Void pointer to `self`:
|
||||
let context = Unmanaged.passUnretained(self).toOpaque()
|
||||
|
||||
// Install handler.
|
||||
InstallEventHandler(GetApplicationEventTarget(), {(nextHanlder, theEvent, userContext) -> OSStatus in
|
||||
// Extract pointer to `self` from void pointer:
|
||||
let mySelf = Unmanaged<AppDelegate>.fromOpaque(userContext!).takeUnretainedValue()
|
||||
|
||||
switch Globals.proxyType {
|
||||
case .pac:
|
||||
Globals.proxyType = .global
|
||||
UserDefaults.standard.setValue("global", forKey: "ShadowsocksRunningMode")
|
||||
mySelf.isNameTextField.stringValue = "Gobal Mode"
|
||||
mySelf.updateRunningModeMenu()
|
||||
mySelf.applyConfig()
|
||||
case .global:
|
||||
Globals.proxyType = .pac
|
||||
UserDefaults.standard.setValue("auto", forKey: "ShadowsocksRunningMode")
|
||||
mySelf.isNameTextField.stringValue = "Auto Mode"
|
||||
mySelf.updateRunningModeMenu()
|
||||
mySelf.applyConfig()
|
||||
}
|
||||
|
||||
mySelf.fadeInHud()
|
||||
|
||||
return noErr
|
||||
}, 1, &eventType, context, nil)
|
||||
|
||||
// Register hotkey.
|
||||
RegisterEventHotKey(UInt32(keyCode),
|
||||
UInt32(modifierKeys),
|
||||
gMyHotKeyID,
|
||||
GetApplicationEventTarget(),
|
||||
0,
|
||||
&hotKeyRef)
|
||||
}
|
||||
|
||||
func fourCharCodeFrom(string: String) -> FourCharCode {
|
||||
assert(string.characters.count == 4, "String length must be 4")
|
||||
var result: FourCharCode = 0
|
||||
for char in string.utf16 {
|
||||
result = (result << 8) + FourCharCode(char)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// MARK: - UI Methods
|
||||
@IBAction func toggleRunning(_ sender: NSMenuItem) {
|
||||
let defaults = UserDefaults.standard
|
||||
var isOn = defaults.bool(forKey: "ShadowsocksOn")
|
||||
@ -531,3 +612,93 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
|
||||
}
|
||||
}
|
||||
|
||||
extension AppDelegate {
|
||||
func fadeInHud() -> Void {
|
||||
if timerToFadeOut != nil {
|
||||
timerToFadeOut?.invalidate()
|
||||
timerToFadeOut = nil
|
||||
}
|
||||
|
||||
fadingOut = false
|
||||
|
||||
hudWindow.orderFrontRegardless()
|
||||
|
||||
CATransaction.begin()
|
||||
CATransaction.setAnimationDuration(kHudFadeInDuration)
|
||||
CATransaction.setCompletionBlock { self.didFadeIn() }
|
||||
panelView.layer?.opacity = 1.0
|
||||
CATransaction.commit()
|
||||
}
|
||||
|
||||
func didFadeIn() -> Void {
|
||||
timerToFadeOut = Timer.scheduledTimer(
|
||||
timeInterval: kHudDisplayDuration,
|
||||
target: self,
|
||||
selector: #selector(fadeOutHud),
|
||||
userInfo: nil,
|
||||
repeats: false)
|
||||
}
|
||||
|
||||
func fadeOutHud() -> Void {
|
||||
fadingOut = true
|
||||
|
||||
CATransaction.begin()
|
||||
CATransaction.setAnimationDuration(kHudFadeOutDuration)
|
||||
CATransaction.setCompletionBlock { self.didFadeOut() }
|
||||
panelView.layer?.opacity = 0.0
|
||||
CATransaction.commit()
|
||||
}
|
||||
|
||||
func didFadeOut() -> Void {
|
||||
if fadingOut {
|
||||
self.hudWindow.orderOut(nil)
|
||||
}
|
||||
fadingOut = false
|
||||
}
|
||||
|
||||
func setupHud() -> Void {
|
||||
isNameTextField.stringValue = "Global Mode"
|
||||
isNameTextField.sizeToFit()
|
||||
|
||||
var labelFrame: CGRect = isNameTextField.frame
|
||||
var hudWindowFrame: CGRect = hudWindow.frame
|
||||
hudWindowFrame.size.width = labelFrame.size.width + kHudHorizontalMargin * 2
|
||||
hudWindowFrame.size.height = kHudHeight
|
||||
|
||||
let screenRect: NSRect = NSScreen.screens()![0].visibleFrame
|
||||
hudWindowFrame.origin.x = (screenRect.size.width - hudWindowFrame.size.width) / 2
|
||||
hudWindowFrame.origin.y = (screenRect.size.height - hudWindowFrame.size.height) / 2
|
||||
hudWindow.setFrame(hudWindowFrame, display: true)
|
||||
|
||||
var viewFrame: NSRect = hudWindowFrame;
|
||||
viewFrame.origin.x = 0
|
||||
viewFrame.origin.y = 0
|
||||
panelView.frame = viewFrame
|
||||
|
||||
labelFrame.origin.x = kHudHorizontalMargin
|
||||
labelFrame.origin.y = (hudWindowFrame.size.height - labelFrame.size.height) / 2
|
||||
isNameTextField.frame = labelFrame
|
||||
}
|
||||
|
||||
func initUIComponent() -> Void {
|
||||
hudWindow.isOpaque = false
|
||||
hudWindow.backgroundColor = .clear
|
||||
hudWindow.level = Int(CGWindowLevelForKey(.utilityWindow)) + 1000
|
||||
hudWindow.styleMask = .borderless
|
||||
hudWindow.hidesOnDeactivate = false
|
||||
hudWindow.collectionBehavior = .canJoinAllSpaces
|
||||
|
||||
let viewLayer: CALayer = CALayer()
|
||||
viewLayer.backgroundColor = CGColor.init(red: 0.05, green: 0.05, blue: 0.05, alpha: kHudAlphaValue)
|
||||
viewLayer.cornerRadius = kHudCornerRadius
|
||||
panelView.wantsLayer = true
|
||||
panelView.layer = viewLayer
|
||||
panelView.layer?.opacity = 0.0
|
||||
|
||||
setupHud()
|
||||
}
|
||||
|
||||
override func awakeFromNib() {
|
||||
initUIComponent()
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11201" systemVersion="16B2548a" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11542" systemVersion="16B2555" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11201"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11542"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||
@ -14,13 +15,15 @@
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="ShadowsocksX_NG" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="RunningStatusMenuItem" destination="fzk-mE-CEV" id="R4x-gK-Qcw"/>
|
||||
<outlet property="autoModeMenuItem" destination="r07-Gu-aEz" id="9aH-pQ-Rgi"/>
|
||||
<outlet property="exportAllServerProfileItem" destination="6k0-gn-DQv" id="W2x-96-ISj"/>
|
||||
<outlet property="globalModeMenuItem" destination="Mw3-Jm-eXA" id="ar5-Yx-3ze"/>
|
||||
<outlet property="importBunchJsonFileItem" destination="T9g-gy-gvv" id="vua-jg-YWe"/>
|
||||
<outlet property="lanchAtLoginMenuItem" destination="eUq-p7-ICK" id="q3D-7x-0db"/>
|
||||
<outlet property="hudWindow" destination="QWV-F6-ac1" id="K6D-a4-oqE"/>
|
||||
<outlet property="isNameTextField" destination="rUN-Nq-HDb" id="ayK-aM-rSa"/>
|
||||
<outlet property="manualModeMenuItem" destination="8PR-gs-c5N" id="9qz-mU-5kt"/>
|
||||
<outlet property="panelView" destination="rai-SH-9tZ" id="5aU-ld-rWb"/>
|
||||
<outlet property="proxyMenuItem" destination="diI-fB-Rss" id="Qjk-9U-3Qy"/>
|
||||
<outlet property="runningStatusMenuItem" destination="fzk-mE-CEV" id="Vwm-Rg-Ykn"/>
|
||||
<outlet property="scanQRCodeMenuItem" destination="Qe6-bF-paT" id="XHa-pa-nCa"/>
|
||||
@ -185,7 +188,7 @@
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
<point key="canvasLocation" x="22" y="89"/>
|
||||
<point key="canvasLocation" x="-2367" y="-139"/>
|
||||
</menu>
|
||||
<menu id="2oY-e9-q1Z">
|
||||
<items>
|
||||
@ -199,6 +202,30 @@
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
</items>
|
||||
<point key="canvasLocation" x="-2113" y="-132"/>
|
||||
</menu>
|
||||
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" hidesOnDeactivate="YES" oneShot="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="QWV-F6-ac1" customClass="NSPanel">
|
||||
<windowStyleMask key="styleMask" closable="YES" miniaturizable="YES" resizable="YES" utility="YES"/>
|
||||
<rect key="contentRect" x="139" y="81" width="200" height="100"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="877"/>
|
||||
<value key="minSize" type="size" width="200" height="100"/>
|
||||
<value key="maxSize" type="size" width="200" height="100"/>
|
||||
<view key="contentView" id="rai-SH-9tZ" userLabel="Panel View">
|
||||
<rect key="frame" x="0.0" y="0.0" width="200" height="100"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<textField verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="162" translatesAutoresizingMaskIntoConstraints="NO" id="rUN-Nq-HDb" userLabel="Is Name">
|
||||
<rect key="frame" x="17" y="33" width="166" height="31"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="center" title="Label" usesSingleLineMode="YES" id="jcH-j9-Xl3">
|
||||
<font key="font" metaFont="system" size="24"/>
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" name="alternateSelectedControlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
</view>
|
||||
<point key="canvasLocation" x="-2357" y="172"/>
|
||||
</window>
|
||||
</objects>
|
||||
</document>
|
||||
|
@ -51,7 +51,7 @@ class ServerProfileManager: NSObject {
|
||||
|
||||
if activeProfileId != nil {
|
||||
defaults.set(activeProfileId, forKey: "ActiveServerProfileId")
|
||||
writeSSLocalConfFile((getActiveProfile()?.toJsonConfig())!)
|
||||
_ = writeSSLocalConfFile((getActiveProfile()?.toJsonConfig())!)
|
||||
} else {
|
||||
defaults.removeObject(forKey: "ActiveServerProfileId")
|
||||
removeSSLocalConfFile()
|
||||
|
@ -23,3 +23,12 @@ extension Data {
|
||||
return hexBytes.joined(separator: "")
|
||||
}
|
||||
}
|
||||
|
||||
enum ProxyType {
|
||||
case pac
|
||||
case global
|
||||
}
|
||||
|
||||
struct Globals {
|
||||
static var proxyType = ProxyType.pac
|
||||
}
|
||||
|
@ -44,9 +44,9 @@
|
||||
|
||||
"Turn Shadowsocks On" = "打开 Shadowsocks";
|
||||
|
||||
"Proxy - Auto By PAC" = "代理 - PAC自动";
|
||||
"Proxy - Auto By PAC" = "代理 - PAC自动(⌃⌘P)";
|
||||
|
||||
"Proxy - Global" = "代理 - 全局";
|
||||
"Proxy - Global" = "代理 - 全局(⌃⌘P)";
|
||||
|
||||
"Proxy - Manual" = "代理 - 手动";
|
||||
|
||||
|
Reference in New Issue
Block a user