Compare commits

..

3 Commits

Author SHA1 Message Date
Duraid Abdul 3efe25f804 Update LCManager.swift 2022-01-25 17:15:30 -08:00
Duraid Abdul 0a3e28b28f Animation Improvements 2022-01-24 23:09:49 -08:00
Duraid Abdul 009fab95be UserDefaults Support
Signed-off-by: Duraid Abdul <duraidabdul@users.noreply.github.com>
2022-01-24 19:06:49 -08:00
+171 -20
View File
@@ -82,8 +82,8 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
}.startAnimation()
grabberMode = false
UserDefaults.standard.set(consoleView.center.x, forKey: "LocalConsole_X")
UserDefaults.standard.set(consoleView.center.y, forKey: "LocalConsole_Y")
UserDefaults.standard.set(consoleView.center.x, forKey: "LocalConsole.X")
UserDefaults.standard.set(consoleView.center.y, forKey: "LocalConsole.Y")
}), for: .touchUpInside)
consoleView.addSubview(button)
@@ -131,8 +131,8 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
// TODO: Snap to nearest position.
UserDefaults.standard.set(consoleSize.width, forKey: "LocalConsole_Width")
UserDefaults.standard.set(consoleSize.height, forKey: "LocalConsole_Height")
UserDefaults.standard.set(consoleSize.width, forKey: "LocalConsole.Width")
UserDefaults.standard.set(consoleSize.height, forKey: "LocalConsole.Height")
}
}
@@ -267,8 +267,8 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
lazy var initialViewLocation: CGPoint = .zero
func configureConsole() {
consoleSize = CGSize(width: UserDefaults.standard.object(forKey: "LocalConsole_Width") as? CGFloat ?? consoleSize.width,
height: UserDefaults.standard.object(forKey: "LocalConsole_Height") as? CGFloat ?? consoleSize.height)
consoleSize = CGSize(width: UserDefaults.standard.object(forKey: "LocalConsole.Width") as? CGFloat ?? consoleSize.width,
height: UserDefaults.standard.object(forKey: "LocalConsole.Height") as? CGFloat ?? consoleSize.height)
consoleView.layer.shadowRadius = 16
@@ -398,6 +398,7 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
viewController.view.addSubview(consoleView)
UIWindow.swizzleStatusBarAppearanceOverride
SwizzleTool().swizzleContextMenuReverseOrder()
updateConsoleOrigin()
}
@@ -424,8 +425,8 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
}
func snapToCachedEndpoint() {
let cachedConsolePosition = CGPoint(x: UserDefaults.standard.object(forKey: "LocalConsole_X") as? CGFloat ?? possibleEndpoints.first!.x,
y: UserDefaults.standard.object(forKey: "LocalConsole_Y") as? CGFloat ?? possibleEndpoints.first!.y)
let cachedConsolePosition = CGPoint(x: UserDefaults.standard.object(forKey: "LocalConsole.X") as? CGFloat ?? possibleEndpoints.first!.x,
y: UserDefaults.standard.object(forKey: "LocalConsole.Y") as? CGFloat ?? possibleEndpoints.first!.y)
consoleView.center = cachedConsolePosition // Update console center so possibleEndpoints are calculated correctly.
consoleView.center = nearestTargetTo(cachedConsolePosition, possibleTargets: possibleEndpoints)
@@ -742,6 +743,9 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
consoleTextView.attributedText = NSAttributedString(string: string, attributes: attributes)
}
// Displays all UserDefaults keys, including unneeded keys that are included by default.
public var showAllUserDefaultsKeys = false
func makeMenu() -> UIMenu {
let copy = UIAction(title: "Copy",
@@ -773,10 +777,127 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
let consoleActions = UIMenu(title: "", options: .displayInline, children: [clear, resize])
var frameSymbol = "rectangle.3.offgrid"
var debugActions: [UIMenuElement] = []
if #available(iOS 15, *) {
frameSymbol = "square.inset.filled"
let deferredUserDefaultsList = UIDeferredMenuElement.uncached { completion in
var actions: [UIAction] = []
let keys: [String] = {
if self.showAllUserDefaultsKeys {
return UserDefaults.standard.dictionaryRepresentation().map { $0.key }
}
// Show keys the developer has added to the app (+ LocalConsole keys), excluding all of Apple's keys.
if let bundle: String = Bundle.main.bundleIdentifier {
let preferencePath: String = NSHomeDirectory() + "/Library/Preferences/\(bundle).plist"
let _keys = NSDictionary(contentsOfFile: preferencePath)?.allKeys as! [String]
return _keys.filter {
!$0.contains("LocalConsole.")
}
}
return []
}()
if keys.isEmpty {
actions.append(UIAction(title: "No Entries",
image: nil, attributes: .disabled, handler: { _ in }
))
} else {
for key in keys.sorted(by: { $0.lowercased() < $1.lowercased() }) {
// Old LocalConsole Key Cleanup
guard !key.contains("LocalConsole_") else {
UserDefaults.standard.removeObject(forKey: key)
continue
}
if let value = UserDefaults.standard.value(forKey: key) {
let action = UIAction(title: key, image: nil) { _ in
let alertController = UIAlertController(title: key,
message: nil,
preferredStyle: .alert)
let headerParagraphStyle = NSMutableParagraphStyle()
headerParagraphStyle.paragraphSpacing = 6
let contentParagraphStyle = NSMutableParagraphStyle()
let attributes: [NSAttributedString.Key: Any] = [
.paragraphStyle: contentParagraphStyle,
.foregroundColor: UIColor.label,
.font: UIFont.systemFont(ofSize: 13, weight: .semibold, design: .monospaced)
]
let attributedTitle: NSMutableAttributedString = {
let attributedString = NSMutableAttributedString(string: "Key\n" + key, attributes: attributes)
attributedString.addAttributes(
[NSAttributedString.Key.foregroundColor : UIColor.label.withAlphaComponent(0.5),
NSAttributedString.Key.paragraphStyle : headerParagraphStyle],
range: NSRange(location: 0, length: 3))
return attributedString
}()
let attributedMessage: NSMutableAttributedString = {
let attributedString = NSMutableAttributedString(string: "\nValue\n" + "\(value)", attributes: attributes)
attributedString.addAttributes(
[NSAttributedString.Key.foregroundColor : UIColor.label.withAlphaComponent(0.5),
NSAttributedString.Key.paragraphStyle : headerParagraphStyle],
range: NSRange(location: 0, length: 7))
return attributedString
}()
alertController.setValue(attributedTitle, forKey: "attributedTitle")
alertController.setValue(attributedMessage, forKey: "attributedMessage")
alertController.addAction(UIAlertAction(title: "Copy Value", style: .default, handler: { _ in
UIPasteboard.general.string = "\(value)"
}))
alertController.addAction(UIAlertAction(title: "Clear Value", style: .destructive, handler: { _ in
UserDefaults.standard.removeObject(forKey: key)
}))
alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { _ in
}))
self.viewController.present(alertController,
animated: true)
}
action.subtitle = "\(value)"
actions.append(action)
}
}
actions.append(
UIAction(title: "Clear Defaults",
image: UIImage(systemName: "trash"), attributes: .destructive, handler: { _ in
keys.forEach {
UserDefaults.standard.removeObject(forKey: $0)
}
})
)
}
completion(actions)
}
let userDefaults = UIMenu(title: "UserDefaults", image: UIImage(systemName: "doc.badge.gearshape"), children: [deferredUserDefaultsList])
debugActions.append(userDefaults)
}
let viewFrames = UIAction(title: debugBordersEnabled ? "Hide View Frames" : "Show View Frames",
image: UIImage(systemName: frameSymbol), handler: { _ in
self.debugBordersEnabled.toggle()
@@ -840,9 +961,11 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
}
})
let debugActions = UIMenu(title: "", options: .displayInline,
debugActions.append(contentsOf: [viewFrames, systemReport, displayReport, respring])
let debugMenu = UIMenu(title: "", options: .displayInline,
children: [UIMenu(title: "Debug", image: UIImage(systemName: "ant"),
children: [viewFrames, systemReport, displayReport, respring])])
children: debugActions)])
var menuContent: [UIMenuElement] = []
@@ -851,7 +974,7 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
} else {
menuContent.append(resize)
}
menuContent.append(debugActions)
menuContent.append(debugMenu)
return UIMenu(title: "", children: menuContent)
}
@@ -875,7 +998,7 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
if !grabberMode { scrollLocked = true }
UIViewPropertyAnimator(duration: 0.8, dampingRatio: 0.5) { [self] in
UIViewPropertyAnimator(duration: 0.8, dampingRatio: 0.6) { [self] in
consoleView.transform = .identity
}.startAnimation()
@@ -948,8 +1071,8 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
}
positionAnimator.startAnimation()
UserDefaults.standard.set(nearestTargetPosition.x, forKey: "LocalConsole_X")
UserDefaults.standard.set(nearestTargetPosition.y, forKey: "LocalConsole_Y")
UserDefaults.standard.set(nearestTargetPosition.x, forKey: "LocalConsole.X")
UserDefaults.standard.set(nearestTargetPosition.y, forKey: "LocalConsole.Y")
DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
self.reassessGrabberMode()
@@ -972,15 +1095,16 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
func consolePiPTouchDown() {
guard !grabberMode else { return }
UIViewPropertyAnimator(duration: 1.25, dampingRatio: 0.5) { [self] in
consoleView.transform = .init(scaleX: 0.95, y: 0.95)
UIViewPropertyAnimator(duration: 0.75, dampingRatio: 1) { [self] in
consoleView.transform = .init(scaleX: 0.97, y: 0.97)
}.startAnimation()
}
// Animate touch up.
func consolePiPTouchUp() {
UIViewPropertyAnimator(duration: 0.8, dampingRatio: 0.4) { [self] in
consoleView.transform = .init(scaleX: 1, y: 1)
UIViewPropertyAnimator(duration: scrollLocked ? 0.4 : 0.7, dampingRatio: scrollLocked ? 1 : 0.45) { [self] in
consoleView.transform = .identity
}.startAnimation()
UIViewPropertyAnimator(duration: 0.4, dampingRatio: 1) { [self] in
@@ -1073,7 +1197,7 @@ extension UIWindow {
/// Make sure this window does not have control over the status bar appearance.
static let swizzleStatusBarAppearanceOverride: Void = {
guard let originalMethod = class_getInstanceMethod(UIWindow.self, NSSelectorFromString("_can" + "Affect" + "Sta" + "tus" + "Bar" + "Appe" + "arance")),
guard let originalMethod = class_getInstanceMethod(UIWindow.self, NSSelectorFromString("_can" + "Affect" + "Status" + "Bar" + "Appearance")),
let swizzledMethod = class_getInstanceMethod(UIWindow.self, #selector(swizzled_statusBarAppearance))
else { return }
method_exchangeImplementations(originalMethod, swizzledMethod)
@@ -1084,9 +1208,36 @@ extension UIWindow {
}
}
class SwizzleTool: NSObject {
/// Ensure context menus always show in a non reversed order.
func swizzleContextMenuReverseOrder() {
guard let originalMethod = class_getInstanceMethod(NSClassFromString("_" + "UI" + "Context" + "Menu" + "List" + "View").self, NSSelectorFromString("reverses" + "Action" + "Order")),
let swizzledMethod = class_getInstanceMethod(SwizzleTool.self, #selector(swizzled_reverses_Action_Order))
else { Swift.print("Swizzle Error Occurred"); return }
method_exchangeImplementations(originalMethod, swizzledMethod)
}
@objc func swizzled_reverses_Action_Order() -> Bool {
if let menu = self.value(forKey: "displayed" + "Menu") as? UIMenu,
menu.title == "Debug" || menu.title == "User" + "Defaults" {
return false
}
if let orig = self.value(forKey: "_" + "reverses" + "Action" + "Order") as? Bool {
return orig
}
return false
}
}
class LumaView: UIView {
lazy var visualEffectView: UIView = {
Bundle(path: "/Sys" + "tem/Lib" + "rary/Private" + "Frameworks/Material" + "Kit." + "framework")!.load()
Bundle(path: "/Sys" + "tem/Lib" + "rary/Private" + "Framework" + "s/Material" + "Kit." + "framework")!.load()
let Pill = NSClassFromString("MT" + "Luma" + "Dodge" + "Pill" + "View") as! UIView.Type