Move the ugly toast codes from application delegate to seperated window controller.

This commit is contained in:
Qiu Yuzhou
2017-03-21 00:05:34 +08:00
parent aa7cfc2e14
commit 3b88409c5f
5 changed files with 193 additions and 138 deletions

View File

@ -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()
}
}

View File

@ -3,7 +3,6 @@
<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="NSApplication">
@ -19,11 +18,8 @@
<outlet property="copyHttpProxyExportCmdLineMenuItem" destination="lg6-To-GZA" id="VTb-he-dg4"/>
<outlet property="exportAllServerProfileItem" destination="6k0-gn-DQv" id="W2x-96-ISj"/>
<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="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="runningStatusMenuItem" destination="fzk-mE-CEV" id="Vwm-Rg-Ykn"/>
<outlet property="scanQRCodeMenuItem" destination="Qe6-bF-paT" id="XHa-pa-nCa"/>
<outlet property="serversMenuItem" destination="u5M-hQ-VSc" id="8gp-SY-Y4U"/>
@ -162,28 +158,5 @@
</items>
<point key="canvasLocation" x="-2367" y="-139"/>
</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>
</document>

View 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
}
}

View 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>