Skip to content

Commit 5e0298d

Browse files
committed
feat: send push notifications for invalid coder scheme URIs
1 parent 0050fc7 commit 5e0298d

File tree

3 files changed

+44
-3
lines changed

3 files changed

+44
-3
lines changed

Coder-Desktop/Coder-Desktop/Coder_DesktopApp.swift

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import FluidMenuBarExtra
22
import NetworkExtension
3+
import os
34
import SDWebImageSVGCoder
45
import SDWebImageSwiftUI
56
import SwiftUI
7+
import UserNotifications
68
import VPNLib
79

810
@main
@@ -36,13 +38,16 @@ struct DesktopApp: App {
3638

3739
@MainActor
3840
class AppDelegate: NSObject, NSApplicationDelegate {
41+
private var logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "app-delegate")
3942
private var menuBar: MenuBarController?
4043
let vpn: CoderVPNService
4144
let state: AppState
4245
let fileSyncDaemon: MutagenDaemon
4346
let urlHandler: URLHandler
47+
let notifDelegate: NotifDelegate
4448

4549
override init() {
50+
notifDelegate = NotifDelegate()
4651
vpn = CoderVPNService()
4752
let state = AppState(onChange: vpn.configureTunnelProviderProtocol)
4853
vpn.onStart = {
@@ -67,6 +72,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
6772
}
6873
self.fileSyncDaemon = fileSyncDaemon
6974
urlHandler = URLHandler(state: state, vpn: vpn)
75+
// `delegate` is weak
76+
UNUserNotificationCenter.current().delegate = notifDelegate
7077
}
7178

7279
func applicationDidFinishLaunching(_: Notification) {
@@ -135,9 +142,14 @@ class AppDelegate: NSObject, NSApplicationDelegate {
135142
// We only accept one at time, for now
136143
return
137144
}
138-
do { try urlHandler.handle(url) } catch {
139-
// TODO: Push notification
140-
print(error.description)
145+
do { try urlHandler.handle(url) } catch let handleError {
146+
Task {
147+
do {
148+
try await sendNotification(title: "Failed to open link", body: handleError.description)
149+
} catch let notifError {
150+
logger.error("Failed to send notification (\(handleError.description)): \(notifError)")
151+
}
152+
}
141153
}
142154
}
143155
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import UserNotifications
2+
3+
class NotifDelegate: NSObject, UNUserNotificationCenterDelegate {
4+
override init() {
5+
super.init()
6+
}
7+
8+
// This function is required for notifications to appear as banners whilst the app is running.
9+
// We're effectively forwarding the notification back to the OS
10+
nonisolated func userNotificationCenter(
11+
_: UNUserNotificationCenter,
12+
willPresent _: UNNotification
13+
) async -> UNNotificationPresentationOptions {
14+
[.banner]
15+
}
16+
}
17+
18+
func sendNotification(title: String, body: String) async throws {
19+
let nc = UNUserNotificationCenter.current()
20+
let granted = try await nc.requestAuthorization(options: [.alert, .badge])
21+
guard granted else {
22+
return
23+
}
24+
let content = UNMutableNotificationContent()
25+
content.title = title
26+
content.body = body
27+
try await nc.add(.init(identifier: UUID().uuidString, content: content, trigger: nil))
28+
}

Coder-Desktop/project.yml

+1
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ targets:
147147
com.apple.developer.system-extension.install: true
148148
com.apple.security.application-groups:
149149
- $(TeamIdentifierPrefix)com.coder.Coder-Desktop
150+
aps-environment: development
150151
settings:
151152
base:
152153
ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon # Sets the app icon to "AppIcon".

0 commit comments

Comments
 (0)