-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathCoder_DesktopApp.swift
102 lines (93 loc) · 3.11 KB
/
Coder_DesktopApp.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import FluidMenuBarExtra
import NetworkExtension
import SwiftUI
import VPNLib
@main
struct DesktopApp: App {
@NSApplicationDelegateAdaptor private var appDelegate: AppDelegate
@State private var hidden: Bool = false
var body: some Scene {
MenuBarExtra("", isInserted: $hidden) {
EmptyView()
}
Window("Sign In", id: Windows.login.rawValue) {
LoginForm()
.environmentObject(appDelegate.state)
}
.windowResizability(.contentSize)
SwiftUI.Settings {
SettingsView<CoderVPNService>()
.environmentObject(appDelegate.vpn)
.environmentObject(appDelegate.state)
}
.windowResizability(.contentSize)
}
}
@MainActor
class AppDelegate: NSObject, NSApplicationDelegate {
private var menuBar: MenuBarController?
let vpn: CoderVPNService
let state: AppState
let fileSyncDaemon: MutagenDaemon
override init() {
vpn = CoderVPNService()
state = AppState(onChange: vpn.configureTunnelProviderProtocol)
fileSyncDaemon = MutagenDaemon()
}
func applicationDidFinishLaunching(_: Notification) {
menuBar = .init(menuBarExtra: FluidMenuBarExtra(title: "Coder Desktop", image: "MenuBarIcon") {
VPNMenu<CoderVPNService>().frame(width: 256)
.environmentObject(self.vpn)
.environmentObject(self.state)
})
// Subscribe to system VPN updates
NotificationCenter.default.addObserver(
self,
selector: #selector(vpnDidUpdate(_:)),
name: .NEVPNStatusDidChange,
object: nil
)
Task {
// If there's no NE config, but the user is logged in, such as
// from a previous install, then we need to reconfigure.
if await !vpn.loadNetworkExtensionConfig() {
state.reconfigure()
}
}
// TODO: Start the daemon only once a file sync is configured
Task {
await fileSyncDaemon.start()
}
}
// This function MUST eventually call `NSApp.reply(toApplicationShouldTerminate: true)`
// or return `.terminateNow`
func applicationShouldTerminate(_: NSApplication) -> NSApplication.TerminateReply {
Task {
async let vpnTask: Void = {
if await self.state.stopVPNOnQuit {
await self.vpn.stop()
}
}()
async let fileSyncTask: Void = self.fileSyncDaemon.stop()
_ = await (vpnTask, fileSyncTask)
NSApp.reply(toApplicationShouldTerminate: true)
}
return .terminateLater
}
func applicationShouldTerminateAfterLastWindowClosed(_: NSApplication) -> Bool {
false
}
}
extension AppDelegate {
@objc private func vpnDidUpdate(_ notification: Notification) {
guard let connection = notification.object as? NETunnelProviderSession else {
return
}
vpn.vpnDidUpdate(connection)
menuBar?.vpnDidUpdate(connection)
}
}
@MainActor
func appActivate() {
NSApp.activate()
}