|
1 | | -import AppKit |
2 | | -import FeedKit |
3 | | -import Foundation |
| 1 | +import Sparkle |
4 | 2 | import Logger |
5 | | -import SwiftUI |
6 | 3 |
|
7 | | -let skippedUpdateVersionKey = "skippedUpdateVersion" |
| 4 | +public final class UpdateChecker { |
| 5 | + let updater: SPUUpdater |
| 6 | + let hostBundleFound: Bool |
8 | 7 |
|
9 | | -public struct UpdateChecker { |
10 | | - var skippedUpdateVersion: String? { |
11 | | - UserDefaults.standard.string(forKey: skippedUpdateVersionKey) |
12 | | - } |
13 | | - |
14 | | - public init() {} |
15 | | - |
16 | | - public func checkForUpdate() { |
17 | | - let url = URL(string: "https://github.com/intitni/CopilotForXcode/releases.atom")! |
18 | | - let parser = FeedParser(URL: url) |
19 | | - parser.parseAsync { result in |
20 | | - switch result { |
21 | | - case let .success(.atom(feed)): |
22 | | - if let entry = feed.entries?.first(where: { |
23 | | - guard let title = $0.title else { return false } |
24 | | - return !title.contains("-") |
25 | | - }) { |
26 | | - self.alertIfUpdateAvailable(entry) |
27 | | - } |
28 | | - case let .failure(error): |
29 | | - Logger.updateChecker.error(error) |
30 | | - default: break |
31 | | - } |
| 8 | + public init(hostBundle: Bundle?) { |
| 9 | + if hostBundle == nil { |
| 10 | + hostBundleFound = false |
| 11 | + Logger.updateChecker.error("Host bundle not found") |
| 12 | + } else { |
| 13 | + hostBundleFound = true |
32 | 14 | } |
33 | | - } |
34 | | - |
35 | | - func alertIfUpdateAvailable(_ entry: AtomFeedEntry) { |
36 | | - guard let version = entry.title, |
37 | | - let currentVersion = Bundle.main |
38 | | - .infoDictionary?["CFBundleShortVersionString"] as? String, |
39 | | - version != skippedUpdateVersion, |
40 | | - version.compare(currentVersion, options: .numeric) == .orderedDescending |
41 | | - else { return } |
42 | | - |
43 | | - Task { @MainActor in |
44 | | - let screenFrame = NSScreen.main?.frame ?? .zero |
45 | | - let window = NSWindow( |
46 | | - contentRect: .init( |
47 | | - x: screenFrame.midX, |
48 | | - y: screenFrame.midY + 200, |
49 | | - width: 500, |
50 | | - height: 500 |
51 | | - ), |
52 | | - styleMask: .borderless, |
53 | | - backing: .buffered, |
54 | | - defer: true |
55 | | - ) |
56 | | - window.level = .floating |
57 | | - window.isReleasedWhenClosed = false |
58 | | - window.contentViewController = NSHostingController( |
59 | | - rootView: AlertView(entry: entry, window: window) |
60 | | - ) |
61 | | - window.makeKeyAndOrderFront(nil) |
| 15 | + updater = SPUUpdater( |
| 16 | + hostBundle: hostBundle ?? Bundle.main, |
| 17 | + applicationBundle: Bundle.main, |
| 18 | + userDriver: SPUStandardUserDriver(hostBundle: hostBundle ?? Bundle.main, delegate: nil), |
| 19 | + delegate: nil |
| 20 | + ) |
| 21 | + do { |
| 22 | + try updater.start() |
| 23 | + } catch { |
| 24 | + Logger.updateChecker.error(error.localizedDescription) |
62 | 25 | } |
63 | 26 | } |
64 | | -} |
65 | | - |
66 | | -struct AlertView: View { |
67 | | - let entry: AtomFeedEntry |
68 | | - let window: NSWindow |
69 | | - |
70 | | - var body: some View { |
71 | | - let version = entry.title ?? "0.0.0" |
72 | | - Color.clear.alert( |
73 | | - "Copilot for Xcode \(version) is available!", |
74 | | - isPresented: .constant(true) |
75 | | - ) { |
76 | | - Button { |
77 | | - if let url = URL(string: entry.links?.first?.attributes?.href ?? "") { |
78 | | - NSWorkspace.shared.open(url) |
79 | | - } |
80 | | - window.close() |
81 | | - } label: { |
82 | | - Text("Visit Release Page") |
83 | | - } |
84 | 27 |
|
85 | | - Button { |
86 | | - UserDefaults.standard.set(version, forKey: skippedUpdateVersionKey) |
87 | | - window.close() |
88 | | - } label: { |
89 | | - Text("Skip This Version") |
90 | | - } |
| 28 | + public func checkForUpdates() { |
| 29 | + updater.checkForUpdates() |
| 30 | + } |
91 | 31 |
|
92 | | - Button { window.close() } label: { Text("Cancel") } |
93 | | - } message: { |
94 | | - Text("Would you like to visit the release page?") |
95 | | - } |
| 32 | + public var automaticallyChecksForUpdates: Bool { |
| 33 | + get { updater.automaticallyChecksForUpdates } |
| 34 | + set { updater.automaticallyChecksForUpdates = newValue } |
96 | 35 | } |
97 | 36 | } |
| 37 | + |
0 commit comments