Last active
January 5, 2024 18:24
-
-
Save alin23/e15b6ffc62a85790096f0228c54fd31e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// swiftc -o /tmp/InternetReachable ~/Temp/InternetReachable.swift && /tmp/InternetReachable | |
import AppKit | |
import Cocoa | |
import Foundation | |
import Network | |
private var window: NSWindow = { | |
let w = NSWindow( | |
contentRect: NSRect(x: 0, y: 0, width: NSScreen.main!.frame.width, height: 20), | |
styleMask: [.fullSizeContentView, .borderless], | |
backing: .buffered, | |
defer: false | |
) | |
w.backgroundColor = .clear | |
w.level = NSWindow.Level(Int(CGShieldingWindowLevel())) | |
w.isOpaque = false | |
w.hasShadow = false | |
w.hidesOnDeactivate = false | |
w.ignoresMouseEvents = true | |
w.isReleasedWhenClosed = false | |
w.isMovableByWindowBackground = false | |
w.sharingType = .none | |
w.setAccessibilityRole(.popover) | |
w.setAccessibilitySubrole(.unknown) | |
w.collectionBehavior = [.canJoinAllSpaces, .stationary, .ignoresCycle, .fullScreenDisallowsTiling] | |
return w | |
}() | |
private var windowController = NSWindowController(window: window) | |
private var fader: DispatchWorkItem? { didSet { oldValue?.cancel() } } | |
private var closer: DispatchWorkItem? { didSet { oldValue?.cancel() } } | |
private func mainAsyncAfter(_ duration: TimeInterval, _ action: @escaping () -> Void) -> DispatchWorkItem { | |
let workItem = DispatchWorkItem { action() } | |
DispatchQueue.main.asyncAfter(deadline: .now() + duration, execute: workItem) | |
return workItem | |
} | |
private func drawColoredTopLine(_ color: NSColor, hideAfter: TimeInterval = 5) { | |
DispatchQueue.main.async { | |
lastColor = color | |
lastHideAfter = hideAfter | |
let box = NSBox() | |
box.boxType = .custom | |
box.fillColor = color | |
box.frame = NSRect(x: 0, y: 10, width: NSScreen.main!.frame.width + 10, height: 3) | |
box.shadow = NSShadow() | |
box.shadow!.shadowColor = color | |
box.shadow!.shadowBlurRadius = 3 | |
box.shadow!.shadowOffset = .init(width: 0, height: -2) | |
let containerView = NSView() | |
containerView.frame = NSRect(x: 0, y: 0, width: NSScreen.main!.frame.width + 10, height: 20) | |
containerView.addSubview(box) | |
window.contentView = containerView | |
window.setFrameOrigin(NSPoint(x: NSScreen.main!.frame.minX - 5, y: NSScreen.main!.frame.maxY - 12)) | |
windowController.showWindow(nil) | |
NSAnimationContext.runAnimationGroup { ctx in | |
ctx.duration = 1.0 | |
window.animator().alphaValue = 0.5 | |
} | |
fader?.cancel() | |
closer?.cancel() | |
guard hideAfter > 0 else { return } | |
fader = mainAsyncAfter(hideAfter) { | |
NSAnimationContext.runAnimationGroup { ctx in | |
ctx.duration = 2.0 | |
window.animator().alphaValue = 0.01 | |
} | |
closer = mainAsyncAfter(2.0) { | |
window.alphaValue = 0.0 | |
lastColor = nil | |
lastHideAfter = nil | |
} | |
} | |
} | |
} | |
private var lastColor: NSColor? | |
private var lastHideAfter: TimeInterval? | |
private var lastStatus: NWPath.Status? | |
NotificationCenter.default.addObserver(forName: NSApplication.didChangeScreenParametersNotification, object: nil, queue: nil) { n in | |
guard let color = lastColor, let hideAfter = lastHideAfter else { | |
return | |
} | |
drawColoredTopLine(color, hideAfter: hideAfter) | |
} | |
let monitor = NWPathMonitor() | |
monitor.pathUpdateHandler = { path in | |
guard path.status != lastStatus else { | |
return | |
} | |
lastStatus = path.status | |
switch path.status { | |
case .satisfied: | |
print("Internet connection: ON") | |
drawColoredTopLine(.systemGreen, hideAfter: 5) | |
case .unsatisfied: | |
print("Internet connection: OFF") | |
drawColoredTopLine(.systemRed, hideAfter: 0) | |
case .requiresConnection: | |
print("Internet connection: MAYBE") | |
drawColoredTopLine(.systemOrange, hideAfter: 5) | |
@unknown default: | |
print("Internet connection: UNKNOWN") | |
drawColoredTopLine(.systemYellow, hideAfter: 5) | |
} | |
} | |
monitor.start(queue: DispatchQueue.global()) | |
signal(SIGINT) { _ in | |
monitor.cancel() | |
exit(0) | |
} | |
RunLoop.main.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment