Skip to content

Commit cf85e2f

Browse files
authored
Merge pull request #569 from abiligiri/feature/managed_preferences
Disallow changes to managed preferences
2 parents 1563010 + 6e64db2 commit cf85e2f

11 files changed

Lines changed: 70 additions & 21 deletions

Xcodes/Backend/AppState+Install.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ extension AppState {
1313

1414
// check to see if we should auto install for the user
1515
public func autoInstallIfNeeded() {
16-
guard let storageValue = UserDefaults.standard.object(forKey: "autoInstallation") as? Int, let autoInstallType = AutoInstallationType(rawValue: storageValue) else { return }
17-
16+
guard let storageValue = Current.defaults.get(forKey: "autoInstallation") as? Int, let autoInstallType = AutoInstallationType(rawValue: storageValue) else { return }
17+
1818
if autoInstallType == .none { return }
1919

2020
// get newest xcode version

Xcodes/Backend/AppState+Runtimes.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ extension AppState {
169169
// sets a proper cookie for runtimes
170170
try await validateADCSession(path: downloadPath)
171171

172-
let downloader = Downloader(rawValue: UserDefaults.standard.string(forKey: "downloader") ?? "aria2") ?? .aria2
172+
let downloader = Downloader(rawValue: Current.defaults.string(forKey: "downloader") ?? "aria2") ?? .aria2
173173

174174
let url = URL(string: source)!
175175
let expectedRuntimePath = Path.xcodesApplicationSupport/"\(url.lastPathComponent)"

Xcodes/Backend/AppState.swift

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,23 @@ import DockProgress
1111
import XcodesKit
1212
import LibFido2Swift
1313

14+
enum PreferenceKey: String {
15+
case installPath
16+
case localPath
17+
case unxipExperiment
18+
case createSymLinkOnSelect
19+
case onSelectActionType
20+
case showOpenInRosettaOption
21+
case autoInstallation
22+
case SUEnableAutomaticChecks
23+
case includePrereleaseVersions
24+
case downloader
25+
case dataSource
26+
case xcodeListCategory
27+
28+
func isManaged() -> Bool { UserDefaults.standard.objectIsForced(forKey: self.rawValue) }
29+
}
30+
1431
class AppState: ObservableObject {
1532
private let client = AppleAPI.Client()
1633
internal let runtimeService = RuntimeService()
@@ -67,26 +84,32 @@ class AppState: ObservableObject {
6784
}
6885
}
6986

87+
var disableLocalPathChange: Bool { PreferenceKey.localPath.isManaged() }
88+
7089
@Published var installPath = "" {
7190
didSet {
7291
Current.defaults.set(installPath, forKey: "installPath")
7392
}
7493
}
75-
94+
95+
var disableInstallPathChange: Bool { PreferenceKey.installPath.isManaged() }
96+
7697
@Published var unxipExperiment = false {
7798
didSet {
7899
Current.defaults.set(unxipExperiment, forKey: "unxipExperiment")
79100
}
80101
}
81102

103+
var disableUnxipExperiment: Bool { PreferenceKey.unxipExperiment.isManaged() }
104+
82105
@Published var createSymLinkOnSelect = false {
83106
didSet {
84107
Current.defaults.set(createSymLinkOnSelect, forKey: "createSymLinkOnSelect")
85108
}
86109
}
87110

88111
var createSymLinkOnSelectDisabled: Bool {
89-
return onSelectActionType == .rename
112+
return onSelectActionType == .rename || PreferenceKey.createSymLinkOnSelect.isManaged()
90113
}
91114

92115
@Published var onSelectActionType = SelectedActionType.none {
@@ -99,6 +122,8 @@ class AppState: ObservableObject {
99122
}
100123
}
101124

125+
var onSelectActionTypeDisabled: Bool { PreferenceKey.onSelectActionType.isManaged() }
126+
102127
@Published var showOpenInRosettaOption = false {
103128
didSet {
104129
Current.defaults.set(showOpenInRosettaOption, forKey: "showOpenInRosettaOption")
@@ -179,8 +204,8 @@ class AppState: ObservableObject {
179204
// MARK: Timer
180205
/// Runs a timer every 6 hours when app is open to check if it needs to auto install any xcodes
181206
func setupAutoInstallTimer() {
182-
guard let storageValue = UserDefaults.standard.object(forKey: "autoInstallation") as? Int, let autoInstallType = AutoInstallationType(rawValue: storageValue) else { return }
183-
207+
guard let storageValue = Current.defaults.get(forKey: "autoInstallation") as? Int, let autoInstallType = AutoInstallationType(rawValue: storageValue) else { return }
208+
184209
if autoInstallType == .none { return }
185210

186211
autoInstallTimer = Timer.scheduledTimer(withTimeInterval: 60*60*6, repeats: true) { [weak self] _ in
@@ -546,7 +571,7 @@ class AppState: ObservableObject {
546571
.mapError { $0 as Error }
547572
}
548573
.flatMap { [unowned self] in
549-
self.install(.version(availableXcode), downloader: Downloader(rawValue: UserDefaults.standard.string(forKey: "downloader") ?? "aria2") ?? .aria2)
574+
self.install(.version(availableXcode), downloader: Downloader(rawValue: Current.defaults.string(forKey: "downloader") ?? "aria2") ?? .aria2)
550575
}
551576
.receive(on: DispatchQueue.main)
552577
.sink(
@@ -572,7 +597,7 @@ class AppState: ObservableObject {
572597
func installWithoutLogin(id: Xcode.ID) {
573598
guard let availableXcode = availableXcodes.first(where: { $0.version == id }) else { return }
574599

575-
installationPublishers[id] = self.install(.version(availableXcode), downloader: Downloader(rawValue: UserDefaults.standard.string(forKey: "downloader") ?? "aria2") ?? .aria2)
600+
installationPublishers[id] = self.install(.version(availableXcode), downloader: Downloader(rawValue: Current.defaults.string(forKey: "downloader") ?? "aria2") ?? .aria2)
576601
.receive(on: DispatchQueue.main)
577602
.sink(
578603
receiveCompletion: { [unowned self] completion in

Xcodes/Backend/DataSource.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,6 @@ public enum DataSource: String, CaseIterable, Identifiable, CustomStringConverti
1414
case .xcodeReleases: return "Xcode Releases"
1515
}
1616
}
17+
18+
var isManaged: Bool { PreferenceKey.dataSource.isManaged() }
1719
}

Xcodes/Backend/Downloader.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,6 @@ public enum Downloader: String, CaseIterable, Identifiable, CustomStringConverti
1313
case .aria2: return "aria2"
1414
}
1515
}
16+
17+
var isManaged: Bool { PreferenceKey.downloader.isManaged() }
1618
}

Xcodes/Frontend/Preferences/AdvancedPreferencePane.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ struct AdvancedPreferencePane: View {
3636
self.appState.installPath = path.string
3737
}
3838
}
39+
.disabled(appState.disableInstallPathChange)
3940
Text("InstallPathDescription")
4041
.font(.footnote)
4142
.foregroundStyle(.secondary)
@@ -72,6 +73,7 @@ struct AdvancedPreferencePane: View {
7273
self.appState.localPath = path.string
7374
}
7475
}
76+
.disabled(appState.disableLocalPathChange)
7577
Text("LocalCachePathDescription")
7678
.font(.footnote)
7779
.foregroundStyle(.secondary)
@@ -93,7 +95,8 @@ struct AdvancedPreferencePane: View {
9395
}
9496
.labelsHidden()
9597
.pickerStyle(.inline)
96-
98+
.disabled(appState.onSelectActionTypeDisabled)
99+
97100
Text(appState.onSelectActionType.detailedDescription)
98101
.font(.footnote)
99102
.foregroundStyle(.secondary)

Xcodes/Frontend/Preferences/DownloadPreferencePane.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,16 @@ struct DownloadPreferencePane: View {
1919
}
2020
.labelsHidden()
2121
.fixedSize()
22-
22+
2323
Text("DataSourceDescription")
2424
.font(.footnote)
2525
.foregroundStyle(.secondary)
2626
.fixedSize(horizontal: false, vertical: true)
2727
}
2828
}
2929
.groupBoxStyle(PreferencesGroupBoxStyle())
30-
30+
.disabled(dataSource.isManaged)
31+
3132
GroupBox(label: Text("Downloader")) {
3233
VStack(alignment: .leading) {
3334
Picker("Downloader", selection: $downloader) {
@@ -38,14 +39,15 @@ struct DownloadPreferencePane: View {
3839
}
3940
.labelsHidden()
4041
.fixedSize()
41-
42+
4243
Text("DownloaderDescription")
4344
.font(.footnote)
4445
.foregroundStyle(.secondary)
4546
.fixedSize(horizontal: false, vertical: true)
4647
}
4748
}
4849
.groupBoxStyle(PreferencesGroupBoxStyle())
50+
.disabled(downloader.isManaged)
4951
}
5052
}
5153
}

Xcodes/Frontend/Preferences/ExperiementsPreferencePane.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ struct ExperimentsPreferencePane: View {
1313
"UseUnxipExperiment",
1414
isOn: $appState.unxipExperiment
1515
)
16+
.disabled(appState.disableUnxipExperiment)
1617
Text("FasterUnxipDescription")
1718
.font(.footnote)
1819
.foregroundStyle(.secondary)

Xcodes/Frontend/Preferences/UpdatesPreferencePane.swift

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ struct UpdatesPreferencePane: View {
1515
"AutomaticInstallNewVersion",
1616
isOn: $autoInstallationType.isAutoInstalling
1717
)
18-
18+
.disabled(updater.disableAutoInstallNewVersions)
19+
1920
Toggle(
2021
"IncludePreRelease",
2122
isOn: $autoInstallationType.isAutoInstallingBeta
2223
)
24+
.disabled(updater.disableIncludePrereleaseVersions)
2325
}
2426
.fixedSize(horizontal: false, vertical: true)
2527
}
@@ -34,17 +36,20 @@ struct UpdatesPreferencePane: View {
3436
isOn: $updater.automaticallyChecksForUpdates
3537
)
3638
.fixedSize(horizontal: true, vertical: false)
37-
39+
.disabled(updater.disableAutoUpdateXcodesApp)
40+
3841
Toggle(
3942
"IncludePreRelease",
4043
isOn: $updater.includePrereleaseVersions
4144
)
42-
45+
.disabled(updater.disableAutoUpdateXcodesAppPrereleaseVersions)
46+
4347
Button("CheckNow") {
4448
updater.checkForUpdates()
4549
}
4650
.padding(.top)
47-
51+
.disabled(updater.disableAutoUpdateXcodesApp)
52+
4853
Text(String(format: localizeString("LastChecked"), lastUpdatedString))
4954
.font(.footnote)
5055
.foregroundStyle(.secondary)
@@ -83,12 +88,18 @@ class ObservableUpdater: ObservableObject {
8388
private var lastUpdateCheckDateObservation: NSKeyValueObservation?
8489
@Published var includePrereleaseVersions = false {
8590
didSet {
86-
UserDefaults.standard.setValue(includePrereleaseVersions, forKey: "includePrereleaseVersions")
87-
91+
Current.defaults.set(includePrereleaseVersions, forKey: "includePrereleaseVersions")
92+
8893
updaterDelegate.includePrereleaseVersions = includePrereleaseVersions
8994
}
9095
}
91-
96+
97+
var disableAutoInstallNewVersions: Bool { PreferenceKey.autoInstallation.isManaged() }
98+
var disableIncludePrereleaseVersions: Bool { PreferenceKey.autoInstallation.isManaged() }
99+
100+
var disableAutoUpdateXcodesApp: Bool { PreferenceKey.SUEnableAutomaticChecks.isManaged() }
101+
var disableAutoUpdateXcodesAppPrereleaseVersions: Bool { PreferenceKey.includePrereleaseVersions.isManaged() }
102+
92103
init() {
93104
updater = SPUStandardUpdaterController(startingUpdater: true, updaterDelegate: updaterDelegate, userDriverDelegate: nil).updater
94105

@@ -111,7 +122,7 @@ class ObservableUpdater: ObservableObject {
111122
self.lastUpdateCheckDate = updater.lastUpdateCheckDate
112123
}
113124
)
114-
includePrereleaseVersions = UserDefaults.standard.bool(forKey: "includePrereleaseVersions")
125+
includePrereleaseVersions = Current.defaults.bool(forKey: "includePrereleaseVersions") ?? false
115126
}
116127

117128
func checkForUpdates() {

Xcodes/Frontend/XcodeList/MainToolbar.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ struct MainToolbarModifier: ViewModifier {
4444
}
4545
}
4646
.help("FilterAvailableDescription")
47+
.disabled(category.isManaged)
4748

4849
Button(action: {
4950
isInstalledOnly.toggle()

0 commit comments

Comments
 (0)