From 3b88409c5f9c14e057242b4cff4dc8c46c9752d2 Mon Sep 17 00:00:00 2001 From: Qiu Yuzhou Date: Tue, 21 Mar 2017 00:05:34 +0800 Subject: [PATCH] Move the ugly toast codes from application delegate to seperated window controller. --- ShadowsocksX-NG.xcodeproj/project.pbxproj | 8 ++ ShadowsocksX-NG/AppDelegate.swift | 134 ++++---------------- ShadowsocksX-NG/Base.lproj/MainMenu.xib | 27 ---- ShadowsocksX-NG/ToastWindowController.swift | 120 ++++++++++++++++++ ShadowsocksX-NG/ToastWindowController.xib | 42 ++++++ 5 files changed, 193 insertions(+), 138 deletions(-) create mode 100644 ShadowsocksX-NG/ToastWindowController.swift create mode 100644 ShadowsocksX-NG/ToastWindowController.xib diff --git a/ShadowsocksX-NG.xcodeproj/project.pbxproj b/ShadowsocksX-NG.xcodeproj/project.pbxproj index 1ca3363..db39cba 100755 --- a/ShadowsocksX-NG.xcodeproj/project.pbxproj +++ b/ShadowsocksX-NG.xcodeproj/project.pbxproj @@ -19,6 +19,8 @@ 9B0BFFEE1D0460A70040E62B /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9B0BFFEC1D0460A70040E62B /* MainMenu.xib */; }; 9B0BFFF91D0460A70040E62B /* ShadowsocksX_NGTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B0BFFF81D0460A70040E62B /* ShadowsocksX_NGTests.swift */; }; 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 */; }; 9B3FFF141D0705810019A709 /* Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B3FFF131D0705810019A709 /* Notifications.swift */; }; 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 = ""; }; 9B172A6D1D0ADDE800B87B9A /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; 9B2491B51D0ACC3A003BBECC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/PreferencesWindowController.xib; sourceTree = ""; }; + 9B3546701E802B1200B510B4 /* ToastWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToastWindowController.swift; sourceTree = ""; }; + 9B3546711E802B1200B510B4 /* ToastWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ToastWindowController.xib; sourceTree = ""; }; 9B3FFF0C1D05FEB30019A709 /* Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; }; 9B3FFF131D0705810019A709 /* Notifications.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Notifications.swift; sourceTree = ""; }; 9B3FFF151D072FDE0019A709 /* LaunchAtLoginController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LaunchAtLoginController.h; sourceTree = ""; }; @@ -378,6 +382,8 @@ 9B5831FD1E741969009D5B7D /* PreferencesWinController.swift */, 9B5831FE1E741969009D5B7D /* PreferencesWinController.xib */, 9B86459C1E7C2CAD00A84029 /* ProxyInterfacesViewCtrl.swift */, + 9B3546701E802B1200B510B4 /* ToastWindowController.swift */, + 9B3546711E802B1200B510B4 /* ToastWindowController.xib */, ); name = UI; sourceTree = ""; @@ -559,6 +565,7 @@ C8E42A6E1D4F2CAF0074C7EA /* UserRulesController.xib in Resources */, 9BEEF06A1D04D4D500FC52B3 /* start_ss_local.sh in Resources */, 9B5832111E742632009D5B7D /* kcptun_1.png in Resources */, + 9B3546731E802B1200B510B4 /* ToastWindowController.xib in Resources */, C6D429941DA75988002A5711 /* privoxy in Resources */, C6D429991DA76FBC002A5711 /* privoxy.config.example in Resources */, 9BEEF06B1D04D4D500FC52B3 /* stop_ss_local.sh in Resources */, @@ -736,6 +743,7 @@ 9BA04B231D23D5A5005AAD7F /* ProxyConfTool.m in Sources */, 9B5831FF1E741969009D5B7D /* PreferencesWinController.swift in Sources */, 9BEEF0781D04FE8A00FC52B3 /* LaunchAgentUtils.swift in Sources */, + 9B3546721E802B1200B510B4 /* ToastWindowController.swift in Sources */, 9B9CBCA61E25E1DB00FC61AA /* KcptunProfile.swift in Sources */, C8E42A6C1D4F270A0074C7EA /* UserRulesController.swift in Sources */, ); diff --git a/ShadowsocksX-NG/AppDelegate.swift b/ShadowsocksX-NG/AppDelegate.swift index 4014ad5..6899dc5 100755 --- a/ShadowsocksX-NG/AppDelegate.swift +++ b/ShadowsocksX-NG/AppDelegate.swift @@ -18,6 +18,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele var preferencesWinCtrl: PreferencesWindowController! var editUserRulesWinCtrl: UserRulesController! var allInOnePreferencesWinCtrl: PreferencesWinController! + var toastWindowCtrl: ToastWindowController! var launchAtLoginController: LaunchAtLoginController = LaunchAtLoginController() @@ -46,22 +47,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele @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 - let kProfileMenuItemIndexBase = 100 - var timerToFadeOut: Timer? = nil - var fadingOut: Bool = false - var statusItem: NSStatusItem! - static let StatusItemIconWidth:CGFloat = 20 func applicationDidFinishLaunching(_ aNotification: Notification) { @@ -142,21 +130,23 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele _ = notifyCenter.rx.notification(NOTIFY_SWITCH_PROXY_MODE_SHORTCUT) .subscribe(onNext: { noti in let mode = defaults.string(forKey: "ShadowsocksRunningMode")! + self.updateRunningModeMenu() + self.applyConfig() + + var toastMessage: String!; switch mode { case "auto": defaults.setValue("global", forKey: "ShadowsocksRunningMode") - self.isNameTextField.stringValue = "Global Mode".localized + toastMessage = "Global Mode".localized case "global": defaults.setValue("auto", forKey: "ShadowsocksRunningMode") - self.isNameTextField.stringValue = "Auto Mode By PAC".localized + toastMessage = "Auto Mode By PAC".localized default: defaults.setValue("auto", forKey: "ShadowsocksRunningMode") - self.isNameTextField.stringValue = "Auto Mode By PAC".localized + toastMessage = "Auto Mode By PAC".localized } - self.updateRunningModeMenu() - self.applyConfig() - self.fadeInHud() + self.makeToast(toastMessage) }) _ = notifyCenter.rx.notification(NOTIFY_FOUND_SS_URL) @@ -226,12 +216,11 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele if showToast { if isOn { - self.isNameTextField.stringValue = "Shadowsocks: On".localized + self.makeToast("Shadowsocks: On".localized) } 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 { return true } -} - -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() + + 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() } } + diff --git a/ShadowsocksX-NG/Base.lproj/MainMenu.xib b/ShadowsocksX-NG/Base.lproj/MainMenu.xib index d0d9a1e..c53bf97 100755 --- a/ShadowsocksX-NG/Base.lproj/MainMenu.xib +++ b/ShadowsocksX-NG/Base.lproj/MainMenu.xib @@ -3,7 +3,6 @@ - @@ -19,11 +18,8 @@ - - - @@ -162,28 +158,5 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ShadowsocksX-NG/ToastWindowController.swift b/ShadowsocksX-NG/ToastWindowController.swift new file mode 100644 index 0000000..9715189 --- /dev/null +++ b/ShadowsocksX-NG/ToastWindowController.swift @@ -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 + } +} diff --git a/ShadowsocksX-NG/ToastWindowController.xib b/ShadowsocksX-NG/ToastWindowController.xib new file mode 100644 index 0000000..d68284b --- /dev/null +++ b/ShadowsocksX-NG/ToastWindowController.xib @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +