Move the ugly toast codes from application delegate to seperated window controller.
This commit is contained in:
@ -19,6 +19,8 @@
|
|||||||
9B0BFFEE1D0460A70040E62B /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9B0BFFEC1D0460A70040E62B /* MainMenu.xib */; };
|
9B0BFFEE1D0460A70040E62B /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9B0BFFEC1D0460A70040E62B /* MainMenu.xib */; };
|
||||||
9B0BFFF91D0460A70040E62B /* ShadowsocksX_NGTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B0BFFF81D0460A70040E62B /* ShadowsocksX_NGTests.swift */; };
|
9B0BFFF91D0460A70040E62B /* ShadowsocksX_NGTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B0BFFF81D0460A70040E62B /* ShadowsocksX_NGTests.swift */; };
|
||||||
9B2491B41D0ACC3A003BBECC /* PreferencesWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9B2491B61D0ACC3A003BBECC /* PreferencesWindowController.xib */; };
|
9B2491B41D0ACC3A003BBECC /* PreferencesWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9B2491B61D0ACC3A003BBECC /* PreferencesWindowController.xib */; };
|
||||||
|
9B3546721E802B1200B510B4 /* ToastWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B3546701E802B1200B510B4 /* ToastWindowController.swift */; };
|
||||||
|
9B3546731E802B1200B510B4 /* ToastWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9B3546711E802B1200B510B4 /* ToastWindowController.xib */; };
|
||||||
9B3FFF0D1D05FEB30019A709 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B3FFF0C1D05FEB30019A709 /* Utils.swift */; };
|
9B3FFF0D1D05FEB30019A709 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B3FFF0C1D05FEB30019A709 /* Utils.swift */; };
|
||||||
9B3FFF141D0705810019A709 /* Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B3FFF131D0705810019A709 /* Notifications.swift */; };
|
9B3FFF141D0705810019A709 /* Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B3FFF131D0705810019A709 /* Notifications.swift */; };
|
||||||
9B3FFF171D072FDE0019A709 /* LaunchAtLoginController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B3FFF161D072FDE0019A709 /* LaunchAtLoginController.m */; };
|
9B3FFF171D072FDE0019A709 /* LaunchAtLoginController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B3FFF161D072FDE0019A709 /* LaunchAtLoginController.m */; };
|
||||||
@ -147,6 +149,8 @@
|
|||||||
9B172A6B1D0ADDDD00B87B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = "<group>"; };
|
9B172A6B1D0ADDDD00B87B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
9B172A6D1D0ADDE800B87B9A /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
9B172A6D1D0ADDE800B87B9A /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||||
9B2491B51D0ACC3A003BBECC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/PreferencesWindowController.xib; sourceTree = "<group>"; };
|
9B2491B51D0ACC3A003BBECC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/PreferencesWindowController.xib; sourceTree = "<group>"; };
|
||||||
|
9B3546701E802B1200B510B4 /* ToastWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToastWindowController.swift; sourceTree = "<group>"; };
|
||||||
|
9B3546711E802B1200B510B4 /* ToastWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ToastWindowController.xib; sourceTree = "<group>"; };
|
||||||
9B3FFF0C1D05FEB30019A709 /* Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = "<group>"; };
|
9B3FFF0C1D05FEB30019A709 /* Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = "<group>"; };
|
||||||
9B3FFF131D0705810019A709 /* Notifications.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Notifications.swift; sourceTree = "<group>"; };
|
9B3FFF131D0705810019A709 /* Notifications.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Notifications.swift; sourceTree = "<group>"; };
|
||||||
9B3FFF151D072FDE0019A709 /* LaunchAtLoginController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LaunchAtLoginController.h; sourceTree = "<group>"; };
|
9B3FFF151D072FDE0019A709 /* LaunchAtLoginController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LaunchAtLoginController.h; sourceTree = "<group>"; };
|
||||||
@ -378,6 +382,8 @@
|
|||||||
9B5831FD1E741969009D5B7D /* PreferencesWinController.swift */,
|
9B5831FD1E741969009D5B7D /* PreferencesWinController.swift */,
|
||||||
9B5831FE1E741969009D5B7D /* PreferencesWinController.xib */,
|
9B5831FE1E741969009D5B7D /* PreferencesWinController.xib */,
|
||||||
9B86459C1E7C2CAD00A84029 /* ProxyInterfacesViewCtrl.swift */,
|
9B86459C1E7C2CAD00A84029 /* ProxyInterfacesViewCtrl.swift */,
|
||||||
|
9B3546701E802B1200B510B4 /* ToastWindowController.swift */,
|
||||||
|
9B3546711E802B1200B510B4 /* ToastWindowController.xib */,
|
||||||
);
|
);
|
||||||
name = UI;
|
name = UI;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -559,6 +565,7 @@
|
|||||||
C8E42A6E1D4F2CAF0074C7EA /* UserRulesController.xib in Resources */,
|
C8E42A6E1D4F2CAF0074C7EA /* UserRulesController.xib in Resources */,
|
||||||
9BEEF06A1D04D4D500FC52B3 /* start_ss_local.sh in Resources */,
|
9BEEF06A1D04D4D500FC52B3 /* start_ss_local.sh in Resources */,
|
||||||
9B5832111E742632009D5B7D /* kcptun_1.png in Resources */,
|
9B5832111E742632009D5B7D /* kcptun_1.png in Resources */,
|
||||||
|
9B3546731E802B1200B510B4 /* ToastWindowController.xib in Resources */,
|
||||||
C6D429941DA75988002A5711 /* privoxy in Resources */,
|
C6D429941DA75988002A5711 /* privoxy in Resources */,
|
||||||
C6D429991DA76FBC002A5711 /* privoxy.config.example in Resources */,
|
C6D429991DA76FBC002A5711 /* privoxy.config.example in Resources */,
|
||||||
9BEEF06B1D04D4D500FC52B3 /* stop_ss_local.sh in Resources */,
|
9BEEF06B1D04D4D500FC52B3 /* stop_ss_local.sh in Resources */,
|
||||||
@ -736,6 +743,7 @@
|
|||||||
9BA04B231D23D5A5005AAD7F /* ProxyConfTool.m in Sources */,
|
9BA04B231D23D5A5005AAD7F /* ProxyConfTool.m in Sources */,
|
||||||
9B5831FF1E741969009D5B7D /* PreferencesWinController.swift in Sources */,
|
9B5831FF1E741969009D5B7D /* PreferencesWinController.swift in Sources */,
|
||||||
9BEEF0781D04FE8A00FC52B3 /* LaunchAgentUtils.swift in Sources */,
|
9BEEF0781D04FE8A00FC52B3 /* LaunchAgentUtils.swift in Sources */,
|
||||||
|
9B3546721E802B1200B510B4 /* ToastWindowController.swift in Sources */,
|
||||||
9B9CBCA61E25E1DB00FC61AA /* KcptunProfile.swift in Sources */,
|
9B9CBCA61E25E1DB00FC61AA /* KcptunProfile.swift in Sources */,
|
||||||
C8E42A6C1D4F270A0074C7EA /* UserRulesController.swift in Sources */,
|
C8E42A6C1D4F270A0074C7EA /* UserRulesController.swift in Sources */,
|
||||||
);
|
);
|
||||||
|
@ -18,6 +18,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
|
|||||||
var preferencesWinCtrl: PreferencesWindowController!
|
var preferencesWinCtrl: PreferencesWindowController!
|
||||||
var editUserRulesWinCtrl: UserRulesController!
|
var editUserRulesWinCtrl: UserRulesController!
|
||||||
var allInOnePreferencesWinCtrl: PreferencesWinController!
|
var allInOnePreferencesWinCtrl: PreferencesWinController!
|
||||||
|
var toastWindowCtrl: ToastWindowController!
|
||||||
|
|
||||||
var launchAtLoginController: LaunchAtLoginController = LaunchAtLoginController()
|
var launchAtLoginController: LaunchAtLoginController = LaunchAtLoginController()
|
||||||
|
|
||||||
@ -46,22 +47,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
|
|||||||
@IBOutlet weak var panelView: NSView!
|
@IBOutlet weak var panelView: NSView!
|
||||||
@IBOutlet weak var isNameTextField: NSTextField!
|
@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
|
|
||||||
|
|
||||||
let kProfileMenuItemIndexBase = 100
|
let kProfileMenuItemIndexBase = 100
|
||||||
|
|
||||||
var timerToFadeOut: Timer? = nil
|
|
||||||
var fadingOut: Bool = false
|
|
||||||
|
|
||||||
var statusItem: NSStatusItem!
|
var statusItem: NSStatusItem!
|
||||||
|
|
||||||
static let StatusItemIconWidth:CGFloat = 20
|
static let StatusItemIconWidth:CGFloat = 20
|
||||||
|
|
||||||
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
||||||
@ -142,21 +130,23 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
|
|||||||
_ = notifyCenter.rx.notification(NOTIFY_SWITCH_PROXY_MODE_SHORTCUT)
|
_ = notifyCenter.rx.notification(NOTIFY_SWITCH_PROXY_MODE_SHORTCUT)
|
||||||
.subscribe(onNext: { noti in
|
.subscribe(onNext: { noti in
|
||||||
let mode = defaults.string(forKey: "ShadowsocksRunningMode")!
|
let mode = defaults.string(forKey: "ShadowsocksRunningMode")!
|
||||||
|
self.updateRunningModeMenu()
|
||||||
|
self.applyConfig()
|
||||||
|
|
||||||
|
var toastMessage: String!;
|
||||||
switch mode {
|
switch mode {
|
||||||
case "auto":
|
case "auto":
|
||||||
defaults.setValue("global", forKey: "ShadowsocksRunningMode")
|
defaults.setValue("global", forKey: "ShadowsocksRunningMode")
|
||||||
self.isNameTextField.stringValue = "Global Mode".localized
|
toastMessage = "Global Mode".localized
|
||||||
case "global":
|
case "global":
|
||||||
defaults.setValue("auto", forKey: "ShadowsocksRunningMode")
|
defaults.setValue("auto", forKey: "ShadowsocksRunningMode")
|
||||||
self.isNameTextField.stringValue = "Auto Mode By PAC".localized
|
toastMessage = "Auto Mode By PAC".localized
|
||||||
default:
|
default:
|
||||||
defaults.setValue("auto", forKey: "ShadowsocksRunningMode")
|
defaults.setValue("auto", forKey: "ShadowsocksRunningMode")
|
||||||
self.isNameTextField.stringValue = "Auto Mode By PAC".localized
|
toastMessage = "Auto Mode By PAC".localized
|
||||||
}
|
}
|
||||||
|
|
||||||
self.updateRunningModeMenu()
|
self.makeToast(toastMessage)
|
||||||
self.applyConfig()
|
|
||||||
self.fadeInHud()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
_ = notifyCenter.rx.notification(NOTIFY_FOUND_SS_URL)
|
_ = notifyCenter.rx.notification(NOTIFY_FOUND_SS_URL)
|
||||||
@ -226,12 +216,11 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
|
|||||||
|
|
||||||
if showToast {
|
if showToast {
|
||||||
if isOn {
|
if isOn {
|
||||||
self.isNameTextField.stringValue = "Shadowsocks: On".localized
|
self.makeToast("Shadowsocks: On".localized)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
self.isNameTextField.stringValue = "Shadowsocks: Off".localized
|
self.makeToast("Shadowsocks: Off".localized)
|
||||||
}
|
}
|
||||||
self.fadeInHud()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -573,95 +562,18 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
|
|||||||
, shouldPresent notification: NSUserNotification) -> Bool {
|
, shouldPresent notification: NSUserNotification) -> Bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func makeToast(_ message: String) {
|
||||||
|
if toastWindowCtrl != nil {
|
||||||
|
toastWindowCtrl.close()
|
||||||
|
}
|
||||||
|
toastWindowCtrl = ToastWindowController(windowNibName: "ToastWindowController")
|
||||||
|
toastWindowCtrl.message = message
|
||||||
|
toastWindowCtrl.showWindow(self)
|
||||||
|
NSApp.activate(ignoringOtherApps: true)
|
||||||
|
toastWindowCtrl.window?.makeKeyAndOrderFront(self)
|
||||||
|
toastWindowCtrl.fadeInHud()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 = "Shadowsocks: Off"
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="macosx"/>
|
<deployment identifier="macosx"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<objects>
|
<objects>
|
||||||
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||||
@ -19,11 +18,8 @@
|
|||||||
<outlet property="copyHttpProxyExportCmdLineMenuItem" destination="lg6-To-GZA" id="VTb-he-dg4"/>
|
<outlet property="copyHttpProxyExportCmdLineMenuItem" destination="lg6-To-GZA" id="VTb-he-dg4"/>
|
||||||
<outlet property="exportAllServerProfileItem" destination="6k0-gn-DQv" id="W2x-96-ISj"/>
|
<outlet property="exportAllServerProfileItem" destination="6k0-gn-DQv" id="W2x-96-ISj"/>
|
||||||
<outlet property="globalModeMenuItem" destination="Mw3-Jm-eXA" id="ar5-Yx-3ze"/>
|
<outlet property="globalModeMenuItem" destination="Mw3-Jm-eXA" id="ar5-Yx-3ze"/>
|
||||||
<outlet property="hudWindow" destination="QWV-F6-ac1" id="K6D-a4-oqE"/>
|
|
||||||
<outlet property="importBunchJsonFileItem" destination="T9g-gy-gvv" id="vua-jg-YWe"/>
|
<outlet property="importBunchJsonFileItem" destination="T9g-gy-gvv" id="vua-jg-YWe"/>
|
||||||
<outlet property="isNameTextField" destination="rUN-Nq-HDb" id="ayK-aM-rSa"/>
|
|
||||||
<outlet property="manualModeMenuItem" destination="8PR-gs-c5N" id="9qz-mU-5kt"/>
|
<outlet property="manualModeMenuItem" destination="8PR-gs-c5N" id="9qz-mU-5kt"/>
|
||||||
<outlet property="panelView" destination="rai-SH-9tZ" id="5aU-ld-rWb"/>
|
|
||||||
<outlet property="runningStatusMenuItem" destination="fzk-mE-CEV" id="Vwm-Rg-Ykn"/>
|
<outlet property="runningStatusMenuItem" destination="fzk-mE-CEV" id="Vwm-Rg-Ykn"/>
|
||||||
<outlet property="scanQRCodeMenuItem" destination="Qe6-bF-paT" id="XHa-pa-nCa"/>
|
<outlet property="scanQRCodeMenuItem" destination="Qe6-bF-paT" id="XHa-pa-nCa"/>
|
||||||
<outlet property="serversMenuItem" destination="u5M-hQ-VSc" id="8gp-SY-Y4U"/>
|
<outlet property="serversMenuItem" destination="u5M-hQ-VSc" id="8gp-SY-Y4U"/>
|
||||||
@ -162,28 +158,5 @@
|
|||||||
</items>
|
</items>
|
||||||
<point key="canvasLocation" x="-2367" y="-139"/>
|
<point key="canvasLocation" x="-2367" y="-139"/>
|
||||||
</menu>
|
</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="1680" height="1027"/>
|
|
||||||
<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>
|
</objects>
|
||||||
</document>
|
</document>
|
||||||
|
120
ShadowsocksX-NG/ToastWindowController.swift
Normal file
120
ShadowsocksX-NG/ToastWindowController.swift
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
//
|
||||||
|
// ToastWindowController.swift
|
||||||
|
// ShadowsocksX-NG
|
||||||
|
//
|
||||||
|
// Created by 邱宇舟 on 2017/3/20.
|
||||||
|
// Copyright © 2017年 qiuyuzhou. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
|
||||||
|
class ToastWindowController: NSWindowController {
|
||||||
|
|
||||||
|
var message: String = ""
|
||||||
|
|
||||||
|
@IBOutlet weak var titleTextField: NSTextField!
|
||||||
|
@IBOutlet weak var panelView: NSView!
|
||||||
|
|
||||||
|
let kHudFadeInDuration: Double = 0.25
|
||||||
|
let kHudFadeOutDuration: Double = 0.25
|
||||||
|
let kHudDisplayDuration: Double = 1.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
|
||||||
|
|
||||||
|
override func windowDidLoad() {
|
||||||
|
super.windowDidLoad()
|
||||||
|
|
||||||
|
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
|
||||||
|
if let win = self.window {
|
||||||
|
win.isOpaque = false
|
||||||
|
win.backgroundColor = .clear
|
||||||
|
win.level = Int(CGWindowLevelForKey(.utilityWindow)) + 1000
|
||||||
|
win.styleMask = .borderless
|
||||||
|
win.hidesOnDeactivate = false
|
||||||
|
win.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
|
||||||
|
|
||||||
|
self.titleTextField.stringValue = self.message
|
||||||
|
|
||||||
|
setupHud()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupHud() -> Void {
|
||||||
|
titleTextField.sizeToFit()
|
||||||
|
|
||||||
|
var labelFrame: CGRect = titleTextField.frame
|
||||||
|
var hudWindowFrame: CGRect = self.window!.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
|
||||||
|
self.window!.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
|
||||||
|
titleTextField.frame = labelFrame
|
||||||
|
}
|
||||||
|
|
||||||
|
func fadeInHud() -> Void {
|
||||||
|
if timerToFadeOut != nil {
|
||||||
|
timerToFadeOut?.invalidate()
|
||||||
|
timerToFadeOut = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fadingOut = false
|
||||||
|
|
||||||
|
self.window?.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.window?.orderOut(nil)
|
||||||
|
}
|
||||||
|
fadingOut = false
|
||||||
|
}
|
||||||
|
}
|
42
ShadowsocksX-NG/ToastWindowController.xib
Normal file
42
ShadowsocksX-NG/ToastWindowController.xib
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="macosx"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<objects>
|
||||||
|
<customObject id="-2" userLabel="File's Owner" customClass="ToastWindowController" customModule="ShadowsocksX_NG" customModuleProvider="target">
|
||||||
|
<connections>
|
||||||
|
<outlet property="panelView" destination="KRY-zc-8By" id="a3Z-ll-K4V"/>
|
||||||
|
<outlet property="titleTextField" destination="scG-hz-bja" id="8Dk-Hq-eUS"/>
|
||||||
|
<outlet property="window" destination="kRK-Pd-y69" id="pHW-35-GCT"/>
|
||||||
|
</connections>
|
||||||
|
</customObject>
|
||||||
|
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||||
|
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||||
|
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" hidesOnDeactivate="YES" oneShot="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="kRK-Pd-y69" customClass="NSPanel">
|
||||||
|
<windowStyleMask key="styleMask" closable="YES" miniaturizable="YES" resizable="YES" utility="YES"/>
|
||||||
|
<rect key="contentRect" x="139" y="81" width="300" height="100"/>
|
||||||
|
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
|
||||||
|
<value key="minSize" type="size" width="200" height="100"/>
|
||||||
|
<value key="maxSize" type="size" width="200" height="100"/>
|
||||||
|
<view key="contentView" id="KRY-zc-8By" userLabel="Panel View">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="300" height="100"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<textField verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="162" translatesAutoresizingMaskIntoConstraints="NO" id="scG-hz-bja" userLabel="Is Name">
|
||||||
|
<rect key="frame" x="24" y="33" width="258" 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="eQL-ri-Y7Z">
|
||||||
|
<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="-2307" y="172"/>
|
||||||
|
</window>
|
||||||
|
</objects>
|
||||||
|
</document>
|
Reference in New Issue
Block a user