forked from intitni/CopilotForXcode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathUpdateChecker.swift
More file actions
112 lines (101 loc) · 3.9 KB
/
UpdateChecker.swift
File metadata and controls
112 lines (101 loc) · 3.9 KB
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
103
104
105
106
107
108
109
110
111
112
import AppKit
import Foundation
import os.log
import SwiftUI
struct Release: Codable {
let tag_name: String?
let html_url: String?
let body: String?
let published_at: String?
}
let skippedUpdateVersionKey = "skippedUpdateVersion"
public struct UpdateChecker {
var skippedUpdateVersion: String? {
UserDefaults.standard.string(forKey: skippedUpdateVersionKey)
}
public init() {}
public func checkForUpdate() async {
let url =
URL(string: "https://api.github.com/repos/intitni/CopilotForXcode/releases/latest")!
do {
var request = URLRequest(url: url)
let token = (Bundle.main.infoDictionary?["GITHUB_TOKEN"] as? String) ?? ""
if !token.isEmpty {
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
}
request.setValue("application/vnd.github+json", forHTTPHeaderField: "Accept")
request.setValue("X-GitHub-Api-Version", forHTTPHeaderField: "2022-11-28")
let (data, _) = try await URLSession.shared.data(for: request)
let decoder = JSONDecoder()
let release = try decoder.decode(Release.self, from: data)
guard let version = release.tag_name,
version != skippedUpdateVersion,
version != Bundle.main
.infoDictionary?["CFBundleShortVersionString"] as? String
else { return }
Task { @MainActor in
let alert = NSAlert()
alert.messageText = "Copilot for Xcode \(version) is available!"
alert.informativeText = "Would you like to visit the release page?"
let view = NSHostingView(
rootView:
AccessoryView(releaseNote: release.body)
)
view.frame = .init(origin: .zero, size: .init(width: 400, height: 200))
alert.accessoryView = view
alert.addButton(withTitle: "Visit Release Page")
alert.addButton(withTitle: "Skip This Version")
alert.addButton(withTitle: "Cancel")
alert.alertStyle = .informational
let screenFrame = NSScreen.main?.frame ?? .zero
let window = NSWindow(
contentRect: .init(
x: screenFrame.midX,
y: screenFrame.midY,
width: 1,
height: 1
),
styleMask: .borderless,
backing: .buffered,
defer: true
)
window.level = .statusBar
window.isReleasedWhenClosed = false
alert.beginSheetModal(for: window) { [window] response in
switch response {
case .alertFirstButtonReturn:
if let url = URL(string: release.html_url ?? "") {
NSWorkspace.shared.open(url)
}
case .alertSecondButtonReturn:
UserDefaults.standard.set(version, forKey: skippedUpdateVersionKey)
default:
break
}
window.close()
}
}
} catch {
os_log(.error, "%@", error.localizedDescription)
}
}
}
struct AccessoryView: View {
let releaseNote: String?
var body: some View {
if let releaseNote {
ScrollView {
Text(releaseNote)
.padding()
Spacer()
}
.background(Color(nsColor: .textBackgroundColor))
.overlay {
Rectangle()
.stroke(Color(nsColor: .separatorColor), style: .init(lineWidth: 2))
}
} else {
EmptyView()
}
}
}