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:
naturecodevoid
2023-05-27 21:53:04 -07:00
parent d2c15b5acd
commit 026392dbc7
13 changed files with 341 additions and 199 deletions

View File

@@ -53,6 +53,10 @@ internal enum L10n {
/// Use preferred servers
internal static let usePreferred = L10n.tr("Localizable", "AdvancedSettingsView.AnisetteSettings.usePreferred", fallback: "Use preferred servers")
}
internal enum DangerZone {
/// Debug Logging
internal static let debugLogging = L10n.tr("Localizable", "AdvancedSettingsView.DangerZone.debugLogging", fallback: "Debug Logging")
}
}
internal enum AppAction {
/// Activate
@@ -283,8 +287,8 @@ internal enum L10n {
internal static let title = L10n.tr("Localizable", "DevModeView.title", fallback: "Developer Mode")
/// Temporary File Explorer
internal static let tmpExplorer = L10n.tr("Localizable", "DevModeView.tmpExplorer", fallback: "Temporary File Explorer")
/// Unstable Features are only available on nightly builds or debug builds
internal static let unstableFeaturesNightlyOnly = L10n.tr("Localizable", "DevModeView.unstableFeaturesNightlyOnly", fallback: "Unstable Features are only available on nightly builds or debug builds")
/// Unstable Features are only available on nightly builds, PR builds and debug builds.
internal static let unstableFeaturesNightlyOnly = L10n.tr("Localizable", "DevModeView.unstableFeaturesNightlyOnly", fallback: "Unstable Features are only available on nightly builds, PR builds and debug builds.")
internal enum Minimuxer {
/// AFC File Explorer (check footer for notes)
internal static let afcExplorer = L10n.tr("Localizable", "DevModeView.Minimuxer.afcExplorer", fallback: "AFC File Explorer (check footer for notes)")
@@ -299,6 +303,10 @@ internal enum L10n {
internal static let footer = L10n.tr("Localizable", "DevModeView.Minimuxer.footer", fallback: "Notes on AFC File Explorer:\n- If nothing shows up, check minimuxer logs for error\n- It is currently extremely very unoptimized and may be very slow; a new AFC client is created for every action\n- It is currently limited to a maximum depth of 3 to ensure it doesn't take too long to iterate over everything when you open it\n- Very buggy\n- There are multiple unimplemented actions")
}
}
internal enum ErrorLogView {
/// ErrorLogView
internal static let title = L10n.tr("Localizable", "ErrorLogView.title", fallback: "Error Log")
}
internal enum MyAppsView {
/// MyAppsView
internal static let active = L10n.tr("Localizable", "MyAppsView.active", fallback: "Active")
@@ -339,6 +347,10 @@ internal enum L10n {
}
}
}
internal enum RefreshAttemptsView {
/// RefreshAttemptsView
internal static let title = L10n.tr("Localizable", "RefreshAttemptsView.title", fallback: "Refresh Attempts")
}
internal enum RootView {
/// Browse
internal static let browse = L10n.tr("Localizable", "RootView.browse", fallback: "Browse")
@@ -360,16 +372,22 @@ internal enum L10n {
internal static let credits = L10n.tr("Localizable", "SettingsView.credits", fallback: "Credits")
/// Debug
internal static let debug = L10n.tr("Localizable", "SettingsView.debug", fallback: "Debug")
/// Debug Logging
internal static let debugLogging = L10n.tr("Localizable", "SettingsView.debugLogging", fallback: "Debug Logging")
/// Export Logs
internal static let exportLogs = L10n.tr("Localizable", "SettingsView.exportLogs", fallback: "Export Logs")
/// Refreshing Apps
internal static let refreshingApps = L10n.tr("Localizable", "SettingsView.refreshingApps", fallback: "Refreshing Apps")
/// Enable Background Refresh to automatically refresh apps in the background when connected to WiFi and with Wireguard active.
internal static let refreshingAppsFooter = L10n.tr("Localizable", "SettingsView.refreshingAppsFooter", fallback: "Enable Background Refresh to automatically refresh apps in the background when connected to WiFi and with Wireguard active.")
/// Reset adi.pb
internal static let resetAdiPb = L10n.tr("Localizable", "SettingsView.resetAdiPb", fallback: "Reset adi.pb")
/// Reset Image Cache
internal static let resetImageCache = L10n.tr("Localizable", "SettingsView.resetImageCache", fallback: "Reset Image Cache")
/// Reset Pairing File
internal static let resetPairingFile = L10n.tr("Localizable", "SettingsView.resetPairingFile", fallback: "Reset Pairing File")
/// Show Error Log
internal static let showErrorLog = L10n.tr("Localizable", "SettingsView.showErrorLog", fallback: "Show Error Log")
/// Show Refresh Attempts
internal static let showRefreshAttempts = L10n.tr("Localizable", "SettingsView.showRefreshAttempts", fallback: "Show Refresh Attempts")
/// SwiftUI Redesign
internal static let swiftUIRedesign = L10n.tr("Localizable", "SettingsView.swiftUIRedesign", fallback: "SwiftUI Redesign")
/// Switch to UIKit
@@ -394,6 +412,18 @@ internal enum L10n {
internal static let p2 = L10n.tr("Localizable", "SettingsView.ConnectedAppleID.Footer.p2", fallback: "Your credentials are only sent to Apple's servers and are not accessible by the SideStore Team. Once successfully logged in, the login details are stored securely on your device.")
}
}
internal enum ResetAdiPb {
/// The adi.pb file is used to generate anisette data, which is required to log into an Apple ID. If you are having issues with account related things, you can try this. However, you will be required to do 2FA again. This will do nothing if you are using an older anisette server.
internal static let description = L10n.tr("Localizable", "SettingsView.ResetAdiPb.description", fallback: "The adi.pb file is used to generate anisette data, which is required to log into an Apple ID. If you are having issues with account related things, you can try this. However, you will be required to do 2FA again. This will do nothing if you are using an older anisette server.")
/// Are you sure you want to reset the adi.pb file?
internal static let title = L10n.tr("Localizable", "SettingsView.ResetAdiPb.title", fallback: "Are you sure you want to reset the adi.pb file?")
}
internal enum ResetPairingFile {
/// If you are having issues with SideStore not being able to install/refresh apps or enable JIT, you can try resetting the pairing file. You will need to generate a new pairing file after doing this. SideStore will close when the file has been deleted.
internal static let description = L10n.tr("Localizable", "SettingsView.ResetPairingFile.description", fallback: "If you are having issues with SideStore not being able to install/refresh apps or enable JIT, you can try resetting the pairing file. You will need to generate a new pairing file after doing this. SideStore will close when the file has been deleted.")
/// Are you sure to reset the pairing file?
internal static let title = L10n.tr("Localizable", "SettingsView.ResetPairingFile.title", fallback: "Are you sure to reset the pairing file?")
}
}
internal enum SourcesView {
/// Done
@@ -410,12 +440,12 @@ internal enum L10n {
internal static let trustedSources = L10n.tr("Localizable", "SourcesView.trustedSources", fallback: "Trusted Sources")
}
internal enum UnstableFeaturesView {
/// Unstable Features are features that are currently being tested or still a work-in-progress and not ready for public usage. Because of this, they are only available on nightly builds. By default, all unstable features are off. Additionally, only more stable unstable features are available in Advanced Settings; most are locked behind Developer Mode to ensure normal users don't use them.
/// Unstable Features are features that are currently being tested or still a work-in-progress and not ready for public usage. Because of this, they are only available on nightly builds, PR builds and debug builds. By default, all unstable features are off. Additionally, only more stable unstable features are available in Advanced Settings; most are locked behind Developer Mode to ensure normal users don't use them as they could contain .
///
/// Every unstable feature has a tracking issue, which contains info on what the unstable feature adds and tracks the unstable feature status. To view a tracking issue for an unstable feature, simply click it in the list. **Please use the tracking issue for reporting bugs or giving feedback.**
///
/// **Do not ask for support on using unstable features, you will not receive any help.**
internal static let description = L10n.tr("Localizable", "UnstableFeaturesView.description", fallback: "Unstable Features are features that are currently being tested or still a work-in-progress and not ready for public usage. Because of this, they are only available on nightly builds. By default, all unstable features are off. Additionally, only more stable unstable features are available in Advanced Settings; most are locked behind Developer Mode to ensure normal users don't use them.\n\nEvery unstable feature has a tracking issue, which contains info on what the unstable feature adds and tracks the unstable feature status. To view a tracking issue for an unstable feature, simply click it in the list. **Please use the tracking issue for reporting bugs or giving feedback.**\n\n**Do not ask for support on using unstable features, you will not receive any help.**")
internal static let description = L10n.tr("Localizable", "UnstableFeaturesView.description", fallback: "Unstable Features are features that are currently being tested or still a work-in-progress and not ready for public usage. Because of this, they are only available on nightly builds, PR builds and debug builds. By default, all unstable features are off. Additionally, only more stable unstable features are available in Advanced Settings; most are locked behind Developer Mode to ensure normal users don't use them as they could contain .\n\nEvery unstable feature has a tracking issue, which contains info on what the unstable feature adds and tracks the unstable feature status. To view a tracking issue for an unstable feature, simply click it in the list. **Please use the tracking issue for reporting bugs or giving feedback.**\n\n**Do not ask for support on using unstable features, you will not receive any help.**")
/// There are currently no unstable features available.
internal static let noUnstableFeatures = L10n.tr("Localizable", "UnstableFeaturesView.noUnstableFeatures", fallback: "There are currently no unstable features available.")
/// UnstableFeaturesView

View File

@@ -7,6 +7,7 @@
//
import SwiftUI
import minimuxer
private struct Server: Identifiable {
var id: String { value }
@@ -37,6 +38,9 @@ struct AdvancedSettingsView: View {
@AppStorage("customAnisetteURL")
var selectedAnisetteServer: String = ""
@AppStorage("isDebugLoggingEnabled")
var isDebugLoggingEnabled: Bool = false
var body: some View {
List {
Section {
@@ -60,8 +64,13 @@ struct AdvancedSettingsView: View {
Text(L10n.AdvancedSettingsView.AnisetteSettings.footer)
}
#if UNSTABLE // TODO: remove this once we have more settings for the danger zone.
Section {
Toggle(L10n.AdvancedSettingsView.DangerZone.debugLogging, isOn: self.$isDebugLoggingEnabled)
.onChange(of: self.isDebugLoggingEnabled) { value in
UserDefaults.shared.isDebugLoggingEnabled = value
set_debug(value)
}
#if UNSTABLE
NavigationLink(L10n.UnstableFeaturesView.title) {
UnstableFeaturesView(inDevMode: false)
@@ -71,7 +80,6 @@ struct AdvancedSettingsView: View {
} header: {
Text(L10n.AdvancedSettingsView.dangerZone)
}
#endif
}
.navigationTitle(L10n.AdvancedSettingsView.title)
.enableInjection()

View File

@@ -107,7 +107,7 @@ struct ErrorLogView: View {
}
}
}
.navigationBarTitle("Error Log")
.navigationBarTitle(L10n.ErrorLogView.title)
.toolbar {
ToolbarItemGroup(placement: .navigationBarTrailing) {
ModalNavigationLink {

View File

@@ -55,7 +55,7 @@ struct RefreshAttemptsView: View {
}
}
.background(self.listBackground)
.navigationTitle("Refresh Attempts")
.navigationTitle(L10n.RefreshAttemptsView.title)
}
@ViewBuilder

View File

@@ -31,13 +31,11 @@ struct SettingsView: View {
@AppStorage("isDevModeEnabled")
var isDevModeEnabled: Bool = false
@AppStorage("isDebugLoggingEnabled")
var isDebugLoggingEnabled: Bool = false
@State var isShowingConnectAppleIDView = false
@State var isShowingResetPairingFileConfirmation = false
@State var isShowingDevModePrompt = false
@State var isShowingDevModeMenu = false
@State var isShowingResetAdiPbConfirmation = false
@State var externalURLToShow: URL?
@State var quickLookURL: URL?
@@ -104,7 +102,7 @@ struct SettingsView: View {
}
Section {
NavigationLink("Show Refresh Attempts") {
NavigationLink(L10n.SettingsView.showRefreshAttempts) {
RefreshAttemptsView()
}
@@ -163,7 +161,7 @@ struct SettingsView: View {
}
Section {
NavigationLink("Show Error Log") {
NavigationLink(L10n.SettingsView.showErrorLog) {
ErrorLogView()
}
@@ -171,12 +169,6 @@ struct SettingsView: View {
AdvancedSettingsView()
}
Toggle(L10n.SettingsView.debugLogging, isOn: self.$isDebugLoggingEnabled)
.onChange(of: self.isDebugLoggingEnabled) { value in
UserDefaults.shared.isDebugLoggingEnabled = value
set_debug(value)
}
AsyncFallibleButton(action: self.exportLogs, label: { execute in Text(L10n.SettingsView.exportLogs) })
if MailComposeView.canSendMail {
@@ -191,18 +183,27 @@ struct SettingsView: View {
}
}
SwiftUI.Button(L10n.SettingsView.switchToUIKit, action: self.switchToUIKit)
SwiftUI.Button(L10n.SettingsView.resetImageCache, action: self.resetImageCache)
.foregroundColor(.red)
SwiftUI.Button("Reset Pairing File") {
SwiftUI.Button(L10n.SettingsView.resetPairingFile) {
self.isShowingResetPairingFileConfirmation = true
}
.foregroundColor(.red)
.actionSheet(isPresented: self.$isShowingResetPairingFileConfirmation) {
ActionSheet(title: Text("Are you sure to reset the pairing file?"), message: Text("You can reset the pairing file when you cannot sideload apps or enable JIT. SideStore will close when the file has been deleted."), buttons: [
.destructive(Text("Delete and Reset"), action: self.resetPairingFile),
ActionSheet(title: Text(L10n.SettingsView.ResetPairingFile.title), message: Text(L10n.SettingsView.ResetPairingFile.description), buttons: [
.destructive(Text(L10n.SettingsView.resetPairingFile), action: self.resetPairingFile),
.cancel()
])
}
SwiftUI.Button(L10n.SettingsView.resetAdiPb) {
self.isShowingResetAdiPbConfirmation = true
}
.foregroundColor(.red)
.actionSheet(isPresented: self.$isShowingResetAdiPbConfirmation) {
ActionSheet(title: Text(L10n.SettingsView.ResetAdiPb.title), message: Text(L10n.SettingsView.ResetAdiPb.description), buttons: [
.destructive(Text(L10n.SettingsView.resetAdiPb), action: self.resetAdiPb),
.cancel()
])
}
@@ -225,13 +226,11 @@ struct SettingsView: View {
}
Section {
} footer: {
Section {} footer: {
Text("SideStore \(appVersion)")
.multilineTextAlignment(.center)
.frame(maxWidth: .infinity)
}
}.padding([.bottom], 32)
}
.listStyle(InsetGroupedListStyle())
.navigationTitle(L10n.SettingsView.title)
@@ -253,13 +252,10 @@ struct SettingsView: View {
.enableInjection()
}
// var appleIDSection: some View {
//
// }
func connectAppleID() {
guard let rootViewController = UIApplication.shared.keyWindow?.rootViewController else {
return
@@ -293,13 +289,6 @@ struct SettingsView: View {
}
}
func switchToUIKit() {
let storyboard = UIStoryboard(name: "Main", bundle: .main)
let rootVC = storyboard.instantiateViewController(withIdentifier: "tabBarController") as! TabBarController
UIApplication.shared.keyWindow?.rootViewController = rootVC
}
func resetImageCache() {
do {
let url = try FileManager.default.url(
@@ -334,6 +323,13 @@ struct SettingsView: View {
}
}
func resetAdiPb() {
if Keychain.shared.adiPb != nil {
Keychain.shared.adiPb = nil
print("Cleared adi.pb from keychain")
}
}
func exportLogs() throws {
let path = FileManager.default.documentsDirectory.appendingPathComponent("sidestore.log")
var text = LCManager.shared.currentText

View File

@@ -12,13 +12,20 @@ import SwiftUI
struct UnstableFeaturesView: View {
@ObservedObject private var iO = Inject.observer
// Keeping a cache of the features allows us to reload the view every time we change one
// If we don't reload the view there is a bug where the toggle will be reset to previous value if you go to another tab and then back
@State private var featureCache: [(key: UnstableFeatures.Feature, value: Bool)]
var inDevMode: Bool
init(inDevMode: Bool) {
self.inDevMode = inDevMode
self.featureCache = UnstableFeatures.getFeatures(inDevMode)
}
var body: some View {
List {
let features = UnstableFeatures.getFeatures(inDevMode)
let description = L10n.UnstableFeaturesView.description + (features.count <= 0 ? "\n\n" + L10n.UnstableFeaturesView.noUnstableFeatures : "")
let description = L10n.UnstableFeaturesView.description + (featureCache.count <= 0 ? "\n\n" + L10n.UnstableFeaturesView.noUnstableFeatures : "")
Section {} footer: {
if #available(iOS 15.0, *),
let string = try? AttributedString(markdown: description, options: AttributedString.MarkdownParsingOptions(interpretedSyntax: .inlineOnlyPreservingWhitespace)) {
@@ -28,9 +35,13 @@ struct UnstableFeaturesView: View {
}
}.listRowInsets(EdgeInsets(top: 8, leading: 0, bottom: 8, trailing: 0))
if features.count > 0 {
ForEach(features.sorted(by: { _, _ in true }), id: \.key) { feature, _ in
Toggle(isOn: Binding(get: { UnstableFeatures.enabled(feature) }, set: { newValue in UnstableFeatures.set(feature, enabled: newValue) })) {
if featureCache.count > 0 {
ForEach(featureCache.sorted(by: { _, _ in true }), id: \.key) { feature, _ in
Toggle(isOn: Binding(get: { UnstableFeatures.enabled(feature) }, set: { newValue in
UnstableFeatures.set(feature, enabled: newValue)
// Update the cache so we reload the view (this fixes the toggle resetting to the previous value if you go to another tab and then back)
featureCache = UnstableFeatures.getFeatures(inDevMode)
})) {
Text(String(describing: feature))
let link = "https://github.com/SideStore/SideStore/issues/\(feature.rawValue)"
Link(link, destination: URL(string: link)!)