diff --git a/lara/views/tweaks/TweaksView.swift b/lara/views/tweaks/TweaksView.swift index 3fe0adf7..2b045783 100644 --- a/lara/views/tweaks/TweaksView.swift +++ b/lara/views/tweaks/TweaksView.swift @@ -22,7 +22,7 @@ struct TweaksView: View { NavigationLink("Liquid Glass", destination: LiquidGlassView()) .disabled(!mgr.vfsready) if doubleSystemVersion() < 26.0 { - NavigationLink("SB Customizer", destination: SpringBoardView()) + NavigationLink("SB Customizer", destination: SpringBoardView(mgr: mgr)) .disabled(!mgr.vfsready) } } diff --git a/lara/views/tweaks/sbcustomizer/SpringBoardView.swift b/lara/views/tweaks/sbcustomizer/SpringBoardView.swift index 134e4340..37defa16 100644 --- a/lara/views/tweaks/sbcustomizer/SpringBoardView.swift +++ b/lara/views/tweaks/sbcustomizer/SpringBoardView.swift @@ -6,14 +6,18 @@ // import SwiftUI +import UIKit -var inProgress = false -var CardAnimationSpeed = 0.3 - -func getDefaultStr(forKey: String, defaultValue: String = "Visible") -> String { - let defaults = UserDefaults.standard - - return defaults.string(forKey: forKey) ?? defaultValue +enum SpringBoardOptions: String, CaseIterable { + case DockHidden = "DockHidden" + case HomeBarHidden = "HomeBar" + case FolderBGHidden = "FolderBGHidden" + case FolderBlurDisabled = "FolderBlurDisabled" + case SwitcherBlurDisabled = "SwitcherBlurDisabled" + case CCModuleBackgroundDisabled = "CCModuleBackgroundDisabled" + case PodBackgroundDisabled = "PodBackgroundDisabled" + case NotifBackgroundDisabled = "NotifBackgroundDisabled" + case ShortcutBanner = "ShortcutBanner" } enum OverwritingFileTypes { @@ -24,12 +28,26 @@ enum OverwritingFileTypes { case region } + +struct GeneralOption: Identifiable { + var value: String + var id = UUID() + var key: String + var sbType: SpringboardColorManager.SpringboardType? + var title: String + var shortTitle: String? + var imageName: String + var fileType: OverwritingFileTypes + var options: [String] = [] + var selectedOption: String = "Visible" + + var minimumOS: Int = 14 + + var color: Color = Color.gray + var blur: Double = 30 + } + struct SpringBoardView: View { - // lazyvgrid - private var gridItemLayout = [GridItem(.adaptive(minimum: 150))] - - @State var flippedOption: GeneralOption? - // list of options @State var tweakOptions: [GeneralOption] = [ .init(value: getDefaultStr(forKey: "Dock"), key: "Dock", sbType: .dock, title: NSLocalizedString("Dock", comment: "Springboard tool"), imageName: "dock.rectangle", fileType: OverwritingFileTypes.springboard, options: ["Visible", "Color", "Disabled"]), @@ -44,67 +62,107 @@ struct SpringBoardView: View { .init(value: getDefaultStr(forKey: "NotifShadow"), key: "NotifShadow", sbType: .notifShadow, title: NSLocalizedString("Notification Banner Shadow", comment: "Springboard tool"), shortTitle: "Notification Shadow", imageName: "platter.filled.top.iphone", fileType: OverwritingFileTypes.springboard, options: ["Visible", "Color", "Disabled"]), // .init(value: getDefaultStr(forKey: "ShortcutBanner"), key: "ShortcutBanner", title: NSLocalizedString("Shortcut Notification Banner", comment: "Springboard tool"), imageName: "pencil.slash", fileType: .springboard, options: ["Visible", "Disabled"], minimumOS: 16) ] + + let mgr: laramgr + let replacementPaths: [String: [String]] = [ + SpringBoardOptions.DockHidden.rawValue: ["CoreMaterial.framework/dockDark.materialrecipe", "CoreMaterial.framework/dockLight.materialrecipe"], + SpringBoardOptions.HomeBarHidden.rawValue: ["MaterialKit.framework/Assets.car"], + SpringBoardOptions.FolderBGHidden.rawValue: ["SpringBoardHome.framework/folderLight.materialrecipe", "SpringBoardHome.framework/folderDark.materialrecipe", "SpringBoardHome.framework/folderDarkSimplified.materialrecipe"], + SpringBoardOptions.FolderBlurDisabled.rawValue: ["SpringBoardHome.framework/folderExpandedBackgroundHome.materialrecipe", "SpringBoardHome.framework/folderExpandedBackgroundHomeSimplified.materialrecipe"], + SpringBoardOptions.SwitcherBlurDisabled.rawValue: ["SpringBoard.framework/homeScreenBackdrop-application.materialrecipe", "SpringBoard.framework/homeScreenBackdrop-switcher.materialrecipe"], + SpringBoardOptions.CCModuleBackgroundDisabled.rawValue: ["CoreMaterial.framework/modules.materialrecipe"], + SpringBoardOptions.PodBackgroundDisabled.rawValue: ["SpringBoardHome.framework/podBackgroundViewLight.visualstyleset", "SpringBoardHome.framework/podBackgroundViewDark.visualstyleset"], + SpringBoardOptions.NotifBackgroundDisabled.rawValue: ["CoreMaterial.framework/plattersDark.materialrecipe", "CoreMaterial.framework/platters.materialrecipe"], + SpringBoardOptions.ShortcutBanner.rawValue: ["SpringBoard.framework/BannersAuthorizedBundleIDs.plist"] + ] var body: some View { - GeometryReader { screenGeometry in - ZStack { - Rectangle() - .opacity(0) - .ignoresSafeArea(edges: .all) - .blur(radius: flippedOption == nil ? 0 : 8, opaque: false) - .frame(maxWidth: .infinity, maxHeight: .infinity) - ScrollView { - VStack { - Button { - if flippedOption == nil { - applyTweaks() - } else { - withAnimation(Animation.easeInOut(duration: CardAnimationSpeed)) { - for (i, opt) in tweakOptions.enumerated() { - if opt.title == flippedOption?.title { - tweakOptions[i].animate3d = false - break + NavigationStack { + List { + Section(header: HeaderLabel(text: "Applying", icon: "checkmark")) { + Button("Apply") { + applyTweaks() + } + Button("Reset all") { + for ind in tweakOptions.indices { + tweakOptions[ind].value = "Visible" + tweakOptions[ind].selectedOption = "Visible" + UserDefaults.standard.set("Visible", forKey: tweakOptions[ind].key) + } + applyTweaks() + } + } + ForEach($tweakOptions) { $option in + Section(header: HeaderLabel(text: option.title, icon: option.imageName)) { + Picker("Option", selection: $option.selectedOption) { + ForEach(0.. Bool { @@ -121,408 +179,130 @@ struct SpringBoardView: View { return false } } - + func applyTweaks() { - if !inProgress { - //UIApplication.shared.alert(title: NSLocalizedString("Applying Springboard Tweaks...", comment: ""), body: NSLocalizedString("Please wait...", comment: ""), animated: true, withButton: false) - var failed: Bool = false - for option in tweakOptions { - // apply tweak - if option.value == "Disabled" { - print("Applying tweak \"" + option.title + "\"") - var succeeded = false - if option.sbType != nil { - succeeded = apply(option.sbType!, .gray.opacity(0), 0) - } else { - succeeded = overwriteFile(typeOfFile: option.fileType, fileIdentifier: option.key, true) - } - if succeeded { - print("Successfully applied tweak \"" + option.title + "\"") - } else { - print("Failed to apply tweak \"" + option.title + "\"!!!") - failed = true - } - - } else if option.value == "Visible" { - print("Applying tweak \"" + option.title + "\"") - if option.sbType != nil { - if option.sbType! == .switcher { - let succeeded = apply(option.sbType!, .gray.opacity(1), 20, save: false) - if succeeded { - print("Successfully applied tweak \"" + option.title + "\"") - } else { - print("Failed to apply tweak \"" + option.title + "\"!!!") - } - } else { - do { - try SpringboardColorManager.revertFiles(forType: option.sbType!) - print("Successfully applied tweak \"" + option.title + "\"") - } catch { - print("Failed to apply tweak \"" + option.title + "\"!!!") - print(error.localizedDescription) - } - } - } else { - let succeeded = overwriteFile(typeOfFile: option.fileType, fileIdentifier: option.key, false) + var failed: Bool = false + for option in tweakOptions { + // apply tweak + if option.value == "Disabled" { + print("Applying tweak \"" + option.title + "\"") + var succeeded = false + if option.sbType != nil { + succeeded = apply(option.sbType!, .gray.opacity(0), 0) + } else { + succeeded = overwriteFile(typeOfFile: option.fileType, fileIdentifier: option.key, true) + } + if succeeded { + print("Successfully applied tweak \"" + option.title + "\"") + } else { + print("Failed to apply tweak \"" + option.title + "\"!!!") + failed = true + } + + } else if option.value == "Visible" { + print("Applying tweak \"" + option.title + "\"") + if option.sbType != nil { + if option.sbType! == .switcher { + let succeeded = apply(option.sbType!, .gray.opacity(1), 20, save: false) if succeeded { print("Successfully applied tweak \"" + option.title + "\"") } else { print("Failed to apply tweak \"" + option.title + "\"!!!") } - } - - } else if option.value == "Color" || option.value == "Blur" { - if option.sbType != nil { - print("Applying tweak \"" + option.title + "\"") - let succeeded = apply(option.sbType!, option.color, Int(option.blur)) - if succeeded { + } else { + do { + try SpringboardColorManager.revertFiles(forType: option.sbType!) print("Successfully applied tweak \"" + option.title + "\"") - } else { + } catch { print("Failed to apply tweak \"" + option.title + "\"!!!") - failed = true + print(error.localizedDescription) } - } else { - print("\(option.title) does not have a springboard type!") - failed = true } - } - } - - DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { - //UIApplication.shared.dismissAlert(animated: true) - if failed { - Alertinator.shared.alert(title: "useless ass alert", body: "something failed while applying tweaks") - //UIApplication.shared.alert(body: "An error occurred when applying tweaks") } else { - Alertinator.shared.alert(title: "yayy", body: "it should've worked?") - //UIApplication.shared.alert(title: NSLocalizedString("Successfully applied tweaks", comment: "Successfully applied tweaks"), body: NSLocalizedString("Respring to see changes", comment: "Respring to see changes")) - } - } - } - } - - struct GeneralOption: Identifiable { - var value: String - var id = UUID() - var key: String - var sbType: SpringboardColorManager.SpringboardType? - var title: String - var shortTitle: String? - var imageName: String - var fileType: OverwritingFileTypes - var options: [String] = [] - var selectedOption: String = "Visible" - var flipped: Bool = false - var animate3d: Bool = false - - var minimumOS: Int = 14 - - var color: Color = Color.gray - var blur: Double = 30 - } - - struct SpringBoardOptionView: View { - @Binding var option: GeneralOption - var screenGeom: GeometryProxy - @Binding var flippedOption: GeneralOption? - @Binding var otherOptions: [GeneralOption] - - var body: some View { - return GeometryReader { cardGeometry in - VStack { - Spacer() - ZStack { - FrontSpringBoardView(option: $option, flippedOption: $flippedOption, otherOptions: $otherOptions).opacity(option.flipped ? 0.0 : 1.0) - .frame(width: cardGeometry.size.width, height: cardGeometry.size.height) - .scaleEffect(option.animate3d ? (min(screenGeom.size.width*0.95, screenGeom.size.height*0.95)) / cardGeometry.size.width: 1) - - BackSpringBoardView(option: $option, flippedOption: $flippedOption, screenGeom: screenGeom).opacity(option.flipped ? 1.0 : 0.0) - .frame(width: min(screenGeom.size.width, screenGeom.size.height)*0.95, height: min(screenGeom.size.width, screenGeom.size.height)*0.95) - .scaleEffect(option.animate3d ? 1 : cardGeometry.size.width / (min(screenGeom.size.width*0.95, screenGeom.size.height*0.95))) + let succeeded = overwriteFile(typeOfFile: option.fileType, fileIdentifier: option.key, false) + if succeeded { + print("Successfully applied tweak \"" + option.title + "\"") + } else { + print("Failed to apply tweak \"" + option.title + "\"!!!") } - .modifier(FlipEffect(flipped: $option.flipped, angle: option.animate3d ? 180 : 0, axis: (x: 0.25, y: 1))) - .offset(x: option.animate3d ? -cardGeometry.frame(in: .named("mainFrame")).origin.x + screenGeom.size.width*0.025: -(screenGeom.size.width*0.95)/2 + cardGeometry.size.width/2, y: option.animate3d ? -cardGeometry.frame(in: .named("mainFrame")).origin.y + (screenGeom.size.height)/8: -screenGeom.size.width/2 + cardGeometry.size.height/2) - } - } - .aspectRatio(1, contentMode: .fit) - } - } - - struct FrontSpringBoardView: View { - @Binding var option: GeneralOption - @Binding var flippedOption: GeneralOption? - @Binding var otherOptions: [GeneralOption] - - var body: some View { - return VStack { - VStack { - Image(systemName: option.imageName) - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 24, height: 24) - .foregroundColor(.blue) - .opacity(0.5) - .padding(.top, 28) - - Text(option.title) - .foregroundStyle(Color(.label)) - .lineLimit(2) - .padding(.horizontal) - .minimumScaleFactor(0.5) - .multilineTextAlignment(.center) - - Image(systemName: option.selectedOption == "Disabled" ? "x.circle" : "pencil.circle") - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 24, height: 24) - .foregroundColor(option.selectedOption == "Color" ? .green : .red) - .opacity(option.selectedOption == "Visible" ? 0 : 0.8) - } - .frame(maxWidth: .infinity, maxHeight: .infinity) - .padding(.vertical) - .background(Color(.secondarySystemBackground) - .opacity(1) - ) - .cornerRadius(10) - .onTapGesture { - if flippedOption == nil { - withAnimation(Animation.easeInOut(duration: CardAnimationSpeed)) { - flippedOption = option - option.animate3d.toggle() - } + + } else if option.value == "Color" || option.value == "Blur" { + if option.sbType != nil { + print("Applying tweak \"" + option.title + "\"") + let succeeded = apply(option.sbType!, option.color, Int(option.blur)) + if succeeded { + print("Successfully applied tweak \"" + option.title + "\"") } else { - withAnimation(Animation.easeInOut(duration: CardAnimationSpeed)) { - for (i, opt) in otherOptions.enumerated() { - if opt.title == flippedOption?.title { - otherOptions[i].animate3d = false - break - } - } - flippedOption = nil - } + print("Failed to apply tweak \"" + option.title + "\"!!!") + failed = true } + } else { + print("\(option.title) does not have a springboard type!") + failed = true } } } + if failed { + Alertinator.shared.alert(title: "useless ass alert", body: "something failed while applying tweaks") + } else { + Alertinator.shared.alert(title: "Success!", body: "Respring to see changes.", actionLabel: "Respring", action: { mgr.respring() }) + } } - struct BackSpringBoardView: View { - @Binding var option: GeneralOption - @Binding var flippedOption: GeneralOption? - var screenGeom: GeometryProxy - - var body: some View { - return VStack (alignment: .center) { - HStack { - Text(option.shortTitle ?? option.title) - .font(.title) - .bold() - .padding(.horizontal, 20) - .padding(.top, 20) - Spacer() - } - - ZStack { - Rectangle() - .foregroundColor(Color(.secondarySystemFill)) - .cornerRadius(8) - .frame(width: screenGeom.size.width - 25 - (10 * CGFloat(option.options.count)), height: screenGeom.size.width*0.075) - HStack { - ForEach(0..(typeOfFile: OverwritingFileTypes, fileIdentifier: String, _ value: Value) -> Bool { + // find the path and replace the file + // springboard option + if typeOfFile == OverwritingFileTypes.springboard { + // springboard tweak being applied + if replacementPaths[fileIdentifier] != nil { + var succeeded = true + for path in replacementPaths[fileIdentifier]! { + if fileIdentifier == "HomeBar" && value as? Bool == false { + if let url: URL = Bundle.main.url(forResource: "HomeBarAssets", withExtension: "car") { + do { + let replacementCar = try Data(contentsOf: url) + //try MDC.overwriteFile(at: "/System/Library/PrivateFrameworks/" + path, with: replacementCar) + } catch { + print(error.localizedDescription) + succeeded = false } + } else { + print("Home bar file not found!") + return false } - HStack { - Text("Blur: \(Int(option.blur))") - .frame(width: 125) - Spacer() - Slider(value: $option.blur, in: 0...150, step: 1.0) - .padding(.horizontal) - } - } - - // MARK: Disabled Text - } else if option.selectedOption == "Disabled" { - Image(systemName: "x.circle") - .foregroundColor(.red) - .font(.system(size: 40)) - } - - Spacer() - - Button(action: { - // save - UserDefaults.standard.set(option.selectedOption, forKey: option.key) - option.value = option.selectedOption - if option.selectedOption == "Color" || option.selectedOption == "Blur" { - do { - try SpringboardColorManager.createColor(forType: option.sbType!, color: CIColor(color: UIColor(option.color)), blur: Int(option.blur), asTemp: false) - print("Success") - } catch { - print(error.localizedDescription) - } - } - - // close menu - if flippedOption!.title == option.title { - withAnimation(Animation.easeInOut(duration: CardAnimationSpeed)) { - flippedOption = nil - option.animate3d.toggle() + } else { + let randomGarbage = Data("###".utf8) + + let result = laramgr.shared.lara_overwritefile(target: "/System/Library/PrivateFrameworks/" + path, data: randomGarbage) + + if result.ok { + print("i hope it worked") + } else { + print("it didn't") } + + return true } - }) { - Text("Save") } - //.buttonStyle(TintedButton(color: .blue, fullwidth: true)) - .padding(25) + return succeeded } - .background(Color(.secondarySystemBackground)) - .cornerRadius(10) } + + return true } } -// MARK: sigh -func overwriteFile(typeOfFile: OverwritingFileTypes, fileIdentifier: String, _ value: Value) -> Bool { - // find the path and replace the file - // springboard option - if typeOfFile == OverwritingFileTypes.springboard { - // springboard tweak being applied - if replacementPaths[fileIdentifier] != nil { - var succeeded = true - for path in replacementPaths[fileIdentifier]! { - if fileIdentifier == "HomeBar" && value as? Bool == false { - if let url: URL = Bundle.main.url(forResource: "HomeBarAssets", withExtension: "car") { - do { - let replacementCar = try Data(contentsOf: url) - //try MDC.overwriteFile(at: "/System/Library/PrivateFrameworks/" + path, with: replacementCar) - } catch { - print(error.localizedDescription) - succeeded = false - } - } else { - print("Home bar file not found!") - return false - } - } else { - let randomGarbage = Data("###".utf8) - - let result = laramgr.shared.lara_overwritefile(target: "/System/Library/PrivateFrameworks/" + path, data: randomGarbage) - - if result.ok { - print("i hope it worked") - } else { - print("it didn't") - } - - return true - } - } - return succeeded - } - } +func getDefaultStr(forKey: String, defaultValue: String = "Visible") -> String { + let defaults = UserDefaults.standard - return true -} - -struct FlipEffect: GeometryEffect { - - var animatableData: Double { - get { angle } - set { angle = newValue } - } - - @Binding var flipped: Bool - var angle: Double - let axis: (x: CGFloat, y: CGFloat) - - func effectValue(size: CGSize) -> ProjectionTransform { - - DispatchQueue.main.async { - self.flipped = self.angle >= 90 && self.angle < 270 - } - - let tweakedAngle = flipped ? -180 + angle : angle - let a = CGFloat(Angle(degrees: tweakedAngle).radians) - - var transform3d = CATransform3DIdentity; - transform3d.m34 = -1/max(size.width, size.height) - - transform3d = CATransform3DRotate(transform3d, a, axis.x, axis.y, 0) - transform3d = CATransform3DTranslate(transform3d, -size.width/2.0, -size.height/2.0, 0) - - let affineTransform = ProjectionTransform(CGAffineTransform(translationX: size.width/2.0, y: size.height / 2.0)) - - return ProjectionTransform(transform3d).concatenating(affineTransform) - } -} - -let replacementPaths: [String: [String]] = [ - SpringBoardOptions.DockHidden.rawValue: ["CoreMaterial.framework/dockDark.materialrecipe", "CoreMaterial.framework/dockLight.materialrecipe"], - SpringBoardOptions.HomeBarHidden.rawValue: ["MaterialKit.framework/Assets.car"], - SpringBoardOptions.FolderBGHidden.rawValue: ["SpringBoardHome.framework/folderLight.materialrecipe", "SpringBoardHome.framework/folderDark.materialrecipe", "SpringBoardHome.framework/folderDarkSimplified.materialrecipe"], - SpringBoardOptions.FolderBlurDisabled.rawValue: ["SpringBoardHome.framework/folderExpandedBackgroundHome.materialrecipe", "SpringBoardHome.framework/folderExpandedBackgroundHomeSimplified.materialrecipe"], - SpringBoardOptions.SwitcherBlurDisabled.rawValue: ["SpringBoard.framework/homeScreenBackdrop-application.materialrecipe", "SpringBoard.framework/homeScreenBackdrop-switcher.materialrecipe"], - SpringBoardOptions.CCModuleBackgroundDisabled.rawValue: ["CoreMaterial.framework/modules.materialrecipe"], - SpringBoardOptions.PodBackgroundDisabled.rawValue: ["SpringBoardHome.framework/podBackgroundViewLight.visualstyleset", "SpringBoardHome.framework/podBackgroundViewDark.visualstyleset"], - SpringBoardOptions.NotifBackgroundDisabled.rawValue: ["CoreMaterial.framework/plattersDark.materialrecipe", "CoreMaterial.framework/platters.materialrecipe"], - SpringBoardOptions.ShortcutBanner.rawValue: ["SpringBoard.framework/BannersAuthorizedBundleIDs.plist"] -] - - -enum SpringBoardOptions: String, CaseIterable { - case DockHidden = "DockHidden" - case HomeBarHidden = "HomeBar" - case FolderBGHidden = "FolderBGHidden" - case FolderBlurDisabled = "FolderBlurDisabled" - case SwitcherBlurDisabled = "SwitcherBlurDisabled" - case CCModuleBackgroundDisabled = "CCModuleBackgroundDisabled" - case PodBackgroundDisabled = "PodBackgroundDisabled" - case NotifBackgroundDisabled = "NotifBackgroundDisabled" - case ShortcutBanner = "ShortcutBanner" + return defaults.string(forKey: forKey) ?? defaultValue } -#Preview { - SpringBoardView() -} +func colortohex(_ color: Color) -> String { + let ui = UIColor(color) + var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0 + ui.getRed(&r, green: &g, blue: &b, alpha: &a) + return String(format: "#%02X%02X%02X (%02X)", Int(r*255), Int(g*255), Int(b*255), Int(a*255)) +} \ No newline at end of file