From e29cf19fddc6878f7e24c442f83d6ff0d23fa6b8 Mon Sep 17 00:00:00 2001 From: Roopesh Chander Date: Wed, 16 Jan 2019 01:00:42 +0530 Subject: macOS: Different status bar icon looks for different states - Looks dimmed when no tunnel is active - Looks normal when a tunnel is active - Animates when a tunnel is activating Signed-off-by: Roopesh Chander --- .../WireGuard/UI/macOS/StatusItemController.swift | 66 ++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 WireGuard/WireGuard/UI/macOS/StatusItemController.swift (limited to 'WireGuard/WireGuard/UI/macOS/StatusItemController.swift') diff --git a/WireGuard/WireGuard/UI/macOS/StatusItemController.swift b/WireGuard/WireGuard/UI/macOS/StatusItemController.swift new file mode 100644 index 0000000..2568c15 --- /dev/null +++ b/WireGuard/WireGuard/UI/macOS/StatusItemController.swift @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: MIT +// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved. + +import Cocoa + +class StatusItemController { + var currentTunnel: TunnelContainer? { + didSet { + updateStatusItemImage() + } + } + + let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength) + private let statusBarImageWhenActive = NSImage(named: "StatusBarIcon")! + private let statusBarImageWhenInactive = NSImage(named: "StatusBarIconDimmed")! + + private let animationImages = [ + NSImage(named: "StatusBarIconDot1")!, + NSImage(named: "StatusBarIconDot2")!, + NSImage(named: "StatusBarIconDot3")! + ] + private var animationImageIndex: Int = 0 + private var animationTimer: Timer? + + init() { + updateStatusItemImage() + } + + func updateStatusItemImage() { + guard let currentTunnel = currentTunnel else { + stopActivatingAnimation() + statusItem.button?.image = statusBarImageWhenInactive + return + } + switch currentTunnel.status { + case .inactive: + stopActivatingAnimation() + statusItem.button?.image = statusBarImageWhenInactive + case .active: + stopActivatingAnimation() + statusItem.button?.image = statusBarImageWhenActive + case .activating, .waiting, .reasserting, .restarting: + startActivatingAnimation() + case .deactivating: + break + } + } + + func startActivatingAnimation() { + guard animationTimer == nil else { return } + let timer = Timer(timeInterval: 0.3, repeats: true) { [weak self] _ in + guard let self = self else { return } + self.statusItem.button?.image = self.animationImages[self.animationImageIndex] + self.animationImageIndex = (self.animationImageIndex + 1) % self.animationImages.count + } + RunLoop.main.add(timer, forMode: .default) + animationTimer = timer + } + + func stopActivatingAnimation() { + guard let timer = self.animationTimer else { return } + timer.invalidate() + animationTimer = nil + animationImageIndex = 0 + } +} -- cgit v1.2.3-59-g8ed1b