Files
xcodesApp-mirror/Xcodes/Frontend/Preferences/UpdatesPreferencePane.swift
Anand Biligiri 6e64db26fb Disallow changes to managed preferences
- Define enumerations for preferences that can be managed in an enterprise environment using MDM
- Add methods in AppState to check for managed preferences
- Update Advanced, Download, Experiments and Update preference panes to disable controls
  to modify any of the managed preferences
- Update Xcode category list button to be disabled if preference is managed
2024-06-21 07:17:18 +05:30

162 lines
5.8 KiB
Swift

import AppleAPI
import Sparkle
import SwiftUI
struct UpdatesPreferencePane: View {
@EnvironmentObject var updater: ObservableUpdater
@AppStorage("autoInstallation") var autoInstallationType: AutoInstallationType = .none
var body: some View {
VStack(alignment: .leading, spacing: 20) {
GroupBox(label: Text("Versions")) {
VStack(alignment: .leading) {
Toggle(
"AutomaticInstallNewVersion",
isOn: $autoInstallationType.isAutoInstalling
)
.disabled(updater.disableAutoInstallNewVersions)
Toggle(
"IncludePreRelease",
isOn: $autoInstallationType.isAutoInstallingBeta
)
.disabled(updater.disableIncludePrereleaseVersions)
}
.fixedSize(horizontal: false, vertical: true)
}
.groupBoxStyle(PreferencesGroupBoxStyle())
Divider()
GroupBox(label: Text("AppUpdates")) {
VStack(alignment: .leading) {
Toggle(
"CheckForAppUpdates",
isOn: $updater.automaticallyChecksForUpdates
)
.fixedSize(horizontal: true, vertical: false)
.disabled(updater.disableAutoUpdateXcodesApp)
Toggle(
"IncludePreRelease",
isOn: $updater.includePrereleaseVersions
)
.disabled(updater.disableAutoUpdateXcodesAppPrereleaseVersions)
Button("CheckNow") {
updater.checkForUpdates()
}
.padding(.top)
.disabled(updater.disableAutoUpdateXcodesApp)
Text(String(format: localizeString("LastChecked"), lastUpdatedString))
.font(.footnote)
.foregroundStyle(.secondary)
}
.frame(maxWidth: .infinity, alignment: .leading)
}
.groupBoxStyle(PreferencesGroupBoxStyle())
}
}
private var lastUpdatedString: String {
if let lastUpdatedDate = updater.lastUpdateCheckDate {
return Self.formatter.string(from: lastUpdatedDate)
} else {
return localizeString("Never")
}
}
private static let formatter = configure(DateFormatter()) {
$0.dateStyle = .medium
$0.timeStyle = .medium
}
}
class ObservableUpdater: ObservableObject {
private let updater: SPUUpdater
private let updaterDelegate = UpdaterDelegate()
@Published var automaticallyChecksForUpdates = false {
didSet {
updater.automaticallyChecksForUpdates = automaticallyChecksForUpdates
}
}
private var automaticallyChecksForUpdatesObservation: NSKeyValueObservation?
@Published var lastUpdateCheckDate: Date?
private var lastUpdateCheckDateObservation: NSKeyValueObservation?
@Published var includePrereleaseVersions = false {
didSet {
Current.defaults.set(includePrereleaseVersions, forKey: "includePrereleaseVersions")
updaterDelegate.includePrereleaseVersions = includePrereleaseVersions
}
}
var disableAutoInstallNewVersions: Bool { PreferenceKey.autoInstallation.isManaged() }
var disableIncludePrereleaseVersions: Bool { PreferenceKey.autoInstallation.isManaged() }
var disableAutoUpdateXcodesApp: Bool { PreferenceKey.SUEnableAutomaticChecks.isManaged() }
var disableAutoUpdateXcodesAppPrereleaseVersions: Bool { PreferenceKey.includePrereleaseVersions.isManaged() }
init() {
updater = SPUStandardUpdaterController(startingUpdater: true, updaterDelegate: updaterDelegate, userDriverDelegate: nil).updater
// upgrade from an old sparkle version which set feeds via the updater
// now it uses the `updaterDelegate`
updater.clearFeedURLFromUserDefaults()
automaticallyChecksForUpdatesObservation = updater.observe(
\.automaticallyChecksForUpdates,
options: [.initial, .new, .old],
changeHandler: { [unowned self] updater, change in
guard change.newValue != change.oldValue else { return }
self.automaticallyChecksForUpdates = updater.automaticallyChecksForUpdates
}
)
lastUpdateCheckDateObservation = updater.observe(
\.lastUpdateCheckDate,
options: [.initial, .new, .old],
changeHandler: { [unowned self] updater, change in
self.lastUpdateCheckDate = updater.lastUpdateCheckDate
}
)
includePrereleaseVersions = Current.defaults.bool(forKey: "includePrereleaseVersions") ?? false
}
func checkForUpdates() {
updater.checkForUpdates()
}
}
class UpdaterDelegate: NSObject, SPUUpdaterDelegate {
var includePrereleaseVersions: Bool = false
func feedURLString(for updater: SPUUpdater) -> String? {
if includePrereleaseVersions {
return .prereleaseAppcast
} else {
return .appcast
}
}
}
extension String {
static let appcast = "https://www.xcodes.app/appcast.xml"
static let prereleaseAppcast = "https://www.xcodes.app/appcast_pre.xml"
}
struct UpdatesPreferencePane_Previews: PreviewProvider {
static var previews: some View {
Group {
UpdatesPreferencePane()
.environmentObject(AppState())
.environmentObject(ObservableUpdater())
.frame(maxWidth: 600)
.frame(minHeight: 300)
}
}
}