mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-15 01:33:25 +01:00
More improvements and fixes (see commit description)
- put SwiftUI in an unstable feature - Add Reset adi.pb to SwiftUI settings - Add localizations to more things such as Error Log and Refresh Attempts - Move debug logging into Advanced Settings - Add padding to version text at the bottom of SwiftUI settings - Add some things to Unstable Features such as nesting the Feature enum in UnstableFeatures and allowing on enable/disable hooks - Don't use ObservableObject for UnstableFeatures as it's not needed - fix a bug with unstable features where the toggle would be reverted if you go into another tab and then back - Use SwiftUI advanced settings in UIKit
This commit is contained in:
30
AltStore/Unstable Features/UnstableFeatures+SwiftUI.swift
Normal file
30
AltStore/Unstable Features/UnstableFeatures+SwiftUI.swift
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// UnstableFeatures+SwiftUI.swift
|
||||
// SideStore
|
||||
//
|
||||
// Created by naturecodevoid on 5/25/23.
|
||||
// Copyright © 2023 SideStore. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
import AltStoreCore
|
||||
|
||||
extension UnstableFeatures {
|
||||
class SwiftUI {
|
||||
static func onEnable() {
|
||||
let rootView = RootView()
|
||||
.environment(\.managedObjectContext, DatabaseManager.shared.viewContext)
|
||||
|
||||
UIApplication.shared.keyWindow?.rootViewController = UIHostingController(rootView: rootView)
|
||||
}
|
||||
|
||||
static func onDisable() {
|
||||
let storyboard = UIStoryboard(name: "Main", bundle: .main)
|
||||
let rootVC = storyboard.instantiateViewController(withIdentifier: "tabBarController") as! TabBarController
|
||||
|
||||
UIApplication.shared.keyWindow?.rootViewController = rootVC
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,42 +6,60 @@
|
||||
// Copyright © 2023 SideStore. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Foundation
|
||||
|
||||
// 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
|
||||
//
|
||||
// Unstable features must have a GitHub Issue for tracking progress, PRs and feedback/commenting.
|
||||
class UnstableFeatures {
|
||||
fileprivate struct Metadata {
|
||||
var availableOutsideDevMode = false
|
||||
var onEnable = {}
|
||||
var onDisable = {}
|
||||
}
|
||||
|
||||
case jitUrlScheme = "0"
|
||||
|
||||
/// Dummy variant to ensure there is always at least one variant. DO NOT USE!
|
||||
case dummy = "dummy"
|
||||
|
||||
func availableOutsideDevMode() -> Bool {
|
||||
switch self {
|
||||
// If your unstable feature is stable enough to be used by nightly users who are not alpha testers or developers,
|
||||
// you may want to have it available in the Unstable Features menu in Advanced Settings (outside of dev mode). To do so, add this:
|
||||
//case .yourFeature: return true
|
||||
case .jitUrlScheme: return true
|
||||
enum Feature: String, CaseIterable {
|
||||
// The value will be the GitHub Issue number. For example, "123" would correspond to https://github.com/SideStore/SideStore/issues/123
|
||||
//
|
||||
// Unstable features must have a GitHub Issue for tracking progress, PRs and feedback/bug reporting/commenting.
|
||||
//
|
||||
// Please order the case by the issue number. They will be ordered by issue number (ascending) in the unstable features menu, so please order them the same way here and in `metadata`.
|
||||
|
||||
default: return false
|
||||
case swiftUI = "0"
|
||||
case jitUrlScheme = "00"
|
||||
|
||||
/// Dummy variant to ensure there is always at least one variant. DO NOT USE!
|
||||
case dummy = "dummy"
|
||||
|
||||
fileprivate var metadata: Metadata {
|
||||
switch self {
|
||||
// If your unstable feature is stable enough to be used by nightly users who are not alpha testers or developers,
|
||||
// you may want to have it available in the Unstable Features menu in Advanced Settings (outside of dev mode). To do so, add this:
|
||||
//case .yourFeature: return Metadata(availableOutsideDevMode: true)
|
||||
// You can also add custom hooks for when your feature is enabled or disabled. However, we strongly recommend moving these to a new file. Example: https://github.com/SideStore/SideStore/blob/feature/unstable-features/AltStore/Unstable%20Features/UnstableFeatures+SwiftUI.swift
|
||||
// Please keep the ordering of the cases in this switch statement the same as the ordering of the enum variants!
|
||||
|
||||
case .swiftUI: return Metadata(availableOutsideDevMode: true, onEnable: SwiftUI.onEnable, onDisable: SwiftUI.onDisable)
|
||||
case .jitUrlScheme: return Metadata(availableOutsideDevMode: true)
|
||||
|
||||
default: return Metadata()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class UnstableFeatures: ObservableObject {
|
||||
#if UNSTABLE
|
||||
private static var features: [AvailableUnstableFeature: Bool] = [:]
|
||||
|
||||
static func getFeatures(_ inDevMode: Bool) -> [(key: AvailableUnstableFeature, value: Bool)] {
|
||||
#if UNSTABLE
|
||||
private static var features: [Feature: Bool] = [:]
|
||||
|
||||
static func getFeatures(_ inDevMode: Bool) -> [(key: Feature, value: Bool)] {
|
||||
// Ensure every feature is in the dictionary
|
||||
for feature in Feature.allCases {
|
||||
if features[feature] == nil {
|
||||
features[feature] = false
|
||||
}
|
||||
}
|
||||
|
||||
return features
|
||||
.filter { feature, _ in
|
||||
feature != .dummy &&
|
||||
(inDevMode || feature.availableOutsideDevMode())
|
||||
}.sorted { a, b in a.key.rawValue > b.key.rawValue } // Convert to array of keys and values
|
||||
(inDevMode || feature.metadata.availableOutsideDevMode)
|
||||
}.sorted { a, b in a.key.rawValue > b.key.rawValue } // Convert to array of keys and values (and also sort them by issue number)
|
||||
}
|
||||
|
||||
static func load() {
|
||||
@@ -50,25 +68,17 @@ class UnstableFeatures: ObservableObject {
|
||||
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 }) {
|
||||
if let feature = Feature.allCases.first(where: { feature in String(describing: feature) == rawFeature.key }) {
|
||||
features[feature] = rawFeature.value
|
||||
} else {
|
||||
print("Unknown unstable feature: \(rawFeature.key) = \(rawFeature.value)")
|
||||
}
|
||||
}
|
||||
|
||||
// If there's a new feature that wasn't saved and therefore wasn't loaded, let's set it to false
|
||||
// Technically we shouldn't have to do this because enabled() will fallback to false
|
||||
for feature in AvailableUnstableFeature.allCases {
|
||||
if features[feature] == nil {
|
||||
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 {
|
||||
for feature in Feature.allCases {
|
||||
features[feature] = false
|
||||
}
|
||||
save()
|
||||
@@ -84,14 +94,21 @@ class UnstableFeatures: ObservableObject {
|
||||
print("\(load ? "Loaded" : "Saved") unstable features: \(String(describing: rawFeatures))")
|
||||
}
|
||||
|
||||
static func set(_ feature: AvailableUnstableFeature, enabled: Bool) {
|
||||
static func set(_ feature: Feature, enabled: Bool) {
|
||||
features[feature] = enabled
|
||||
// Let's save before running the hooks... they might crash the app or something
|
||||
save()
|
||||
// Should be no-op for features with the default hooks (they do nothing)
|
||||
if enabled {
|
||||
feature.metadata.onEnable()
|
||||
} else {
|
||||
feature.metadata.onDisable()
|
||||
}
|
||||
}
|
||||
#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 {
|
||||
static func enabled(_ feature: Feature) -> Bool {
|
||||
#if UNSTABLE
|
||||
features[feature] ?? false
|
||||
#else
|
||||
|
||||
Reference in New Issue
Block a user