feat: view to enable/disable Unstable Features

This commit is contained in:
naturecodevoid
2023-05-20 14:23:25 -07:00
parent 9c3461b0c6
commit 637a0354c5
8 changed files with 85 additions and 41 deletions

View File

@@ -6,6 +6,8 @@
// Copyright © 2023 SideStore. All rights reserved.
//
import SwiftUI
// I prefixed it with Available to make UnstableFeatures come up first in autocomplete, feel free to rename it if you know a better name
enum AvailableUnstableFeature: String, CaseIterable {
// The value will be the GitHub Issue number. For example, "123" would correspond to https://github.com/SideStore/SideStore/issues/123
@@ -29,71 +31,58 @@ enum AvailableUnstableFeature: String, CaseIterable {
}
}
class UnstableFeatures {
class UnstableFeatures: ObservableObject {
#if UNSTABLE
private static var features: [AvailableUnstableFeature: Bool] = [:]
#endif
static let shared = UnstableFeatures()
@Published var features: [AvailableUnstableFeature: Bool] = [:]
static func load() {
#if UNSTABLE
if features.count > 0 { return print("It seems unstable features have already been loaded, skipping") }
if shared.features.count > 0 { return print("It seems unstable features have already been loaded, skipping") }
if let rawFeatures = UserDefaults.shared.unstableFeatures,
let rawFeatures = try? JSONDecoder().decode([String: Bool].self, from: rawFeatures) {
for rawFeature in rawFeatures {
if let feature = AvailableUnstableFeature.allCases.first(where: { feature in String(describing: feature) == rawFeature.key }) {
features[feature] = rawFeature.value
shared.features[feature] = rawFeature.value
} else {
print("Unknown unstable feature: \(rawFeature.key) = \(rawFeature.value)")
}
}
for feature in AvailableUnstableFeature.allCases {
if shared.features[feature] == nil {
shared.features[feature] = false
}
}
save(load: true)
} else {
print("Setting all unstable features to false since we couldn't load them from UserDefaults (either they were never saved or there was an error decoding JSON)")
for feature in AvailableUnstableFeature.allCases {
features[feature] = false
shared.features[feature] = false
}
save()
}
#else
print("Unstable features are not available on this build")
#endif
}
private static func save(load: Bool = false) {
#if UNSTABLE
var rawFeatures: [String: Bool] = [:]
for feature in features {
for feature in shared.features {
rawFeatures[String(describing: feature.key)] = feature.value
}
UserDefaults.shared.unstableFeatures = try! JSONEncoder().encode(rawFeatures)
print("\(load ? "Loaded" : "Saved") unstable features: \(String(describing: rawFeatures))")
#else
// we want this to crash, this function should never be triggered on non-unstable builds
fatalError("Tried to save unstable features on non-unstable build!")
#endif
}
static func set(_ feature: AvailableUnstableFeature, enabled: Bool) {
#if UNSTABLE
features[feature] = enabled
shared.features[feature] = enabled
save()
#else
// we want this to crash, this function should never be triggered on non-unstable builds
fatalError("Tried to set unstable feature \(String(describing: feature)) to \(enabled) on non-unstable build!")
#endif
}
#endif
@inline(__always) // hopefully this will help the compiler realize that if statements that use this function should be removed on non-unstable builds
static func enabled(_ feature: AvailableUnstableFeature) -> Bool {
#if UNSTABLE
features[feature] ?? false
shared.features[feature] ?? false
#else
false
#endif