Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 009fab95be | |||
| a1275a7f49 | |||
| e08d439d2b | |||
| da9d78f559 | |||
| 50e4ce4e03 | |||
| ae73be37b4 | |||
| eeece2fda8 |
@@ -21,7 +21,7 @@ let consoleManager = LCManager.shared
|
||||
```
|
||||
|
||||
## **Usage**
|
||||
Once prepared, the localConsole can be used throughout your project.
|
||||
Once prepared, the consoleManager can be used throughout your project.
|
||||
```swift
|
||||
|
||||
// Activate the console view.
|
||||
|
||||
@@ -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
|
||||
@@ -391,7 +391,7 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
|
||||
consoleWindow?.windowLevel = UIWindow.Level.statusBar
|
||||
consoleWindow?.isHidden = false
|
||||
|
||||
viewController = ConsoleViewController()
|
||||
viewController.view = PassthroughView()
|
||||
|
||||
consoleWindow?.rootViewController = viewController
|
||||
|
||||
@@ -424,8 +424,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)
|
||||
@@ -532,12 +532,34 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
var hasShortened = false
|
||||
|
||||
public var isCharacterLimitDisabled = false
|
||||
public var isCharacterLimitWarningDisabled = false
|
||||
|
||||
/// Print items to the console view.
|
||||
public func print(_ items: Any) {
|
||||
if currentText == "" {
|
||||
currentText = "\(items)"
|
||||
let _currentText: String = {
|
||||
if currentText == "" {
|
||||
return "\(items)"
|
||||
} else {
|
||||
return currentText + "\n\(items)"
|
||||
}
|
||||
}()
|
||||
|
||||
// Cut down string if it exceeds 50,000 characters to keep text view running smoothly.
|
||||
if _currentText.count > 50000 && !isCharacterLimitDisabled {
|
||||
|
||||
if !hasShortened && !isCharacterLimitWarningDisabled {
|
||||
hasShortened = true
|
||||
Swift.print("LocalConsole's content has exceeded 50,000 characters.\nTo maintain performance, LCManager cuts down the beginning of the printed content. To disable this behaviour, set LCManager.shared.isCharacterLimitDisabled to true.\nTo disable this warning, set LCManager.shared.isCharacterLimitWarningDisabled = true.")
|
||||
|
||||
}
|
||||
|
||||
let shortenedString = String(_currentText.suffix(50000))
|
||||
currentText = shortenedString.stringAfterFirstOccurenceOf(delimiter: "\n") ?? shortenedString
|
||||
} else {
|
||||
currentText = currentText + "\n\(items)"
|
||||
currentText = _currentText
|
||||
}
|
||||
}
|
||||
|
||||
@@ -720,6 +742,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",
|
||||
@@ -751,10 +776,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 < $1 }) {
|
||||
|
||||
// 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()
|
||||
@@ -818,9 +960,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] = []
|
||||
|
||||
@@ -829,7 +973,9 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
|
||||
} else {
|
||||
menuContent.append(resize)
|
||||
}
|
||||
menuContent.append(debugActions)
|
||||
menuContent.append(debugMenu)
|
||||
|
||||
|
||||
|
||||
return UIMenu(title: "", children: menuContent)
|
||||
}
|
||||
@@ -867,12 +1013,15 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
let consolePiPPanner_frameRateRequest = FrameRateRequest()
|
||||
var consolePiPPanner_frameRateRequestID: UUID?
|
||||
|
||||
@objc func consolePiPPanner(recognizer: UIPanGestureRecognizer) {
|
||||
|
||||
if recognizer.state == .began {
|
||||
consolePiPPanner_frameRateRequest.isActive = true
|
||||
if #available(iOS 15, *) {
|
||||
consolePiPPanner_frameRateRequestID = UUID()
|
||||
FrameRateRequest.shared.activate(id: consolePiPPanner_frameRateRequestID!)
|
||||
}
|
||||
|
||||
initialViewLocation = consoleView.center
|
||||
}
|
||||
@@ -894,8 +1043,12 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
|
||||
|
||||
case .ended, .cancelled:
|
||||
|
||||
consolePiPPanner_frameRateRequest.isActive = false
|
||||
FrameRateRequest().perform(duration: 0.5)
|
||||
if #available(iOS 15, *), let id = consolePiPPanner_frameRateRequestID {
|
||||
consolePiPPanner_frameRateRequestID = nil
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
FrameRateRequest.shared.deactivate(id: id)
|
||||
}
|
||||
}
|
||||
|
||||
// After the PiP is thrown, determine the best corner and re-target it there.
|
||||
let decelerationRate = UIScrollView.DecelerationRate.normal.rawValue
|
||||
@@ -919,8 +1072,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()
|
||||
@@ -995,6 +1148,18 @@ class ConsoleWindow: UIWindow {
|
||||
}
|
||||
}
|
||||
|
||||
// Custom view for the console to appear above other windows while passing touches down.
|
||||
class PassthroughView: UIView {
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
|
||||
if let hitView = super.hitTest(point, with: event) {
|
||||
return hitView.isKind(of: PassthroughView.self) ? nil : hitView
|
||||
}
|
||||
return super.hitTest(point, with: event)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
import UIKit.UIGestureRecognizerSubclass
|
||||
|
||||
@@ -1122,7 +1287,7 @@ class InvertedTextView: UITextView {
|
||||
|
||||
var pendingOffsetChange = false
|
||||
|
||||
// Thanks to WWDC21 Lab!
|
||||
// Thanks to WWDC21 UIKit Lab!
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
@@ -1154,6 +1319,14 @@ extension UIDevice {
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
func stringAfterFirstOccurenceOf(delimiter: String) -> String? {
|
||||
guard let upperIndex = (self.range(of: delimiter)?.upperBound) else { return nil }
|
||||
let trailingString: String = .init(self.suffix(from: upperIndex))
|
||||
return trailingString
|
||||
}
|
||||
}
|
||||
|
||||
extension TimeInterval {
|
||||
var formattedString: String? {
|
||||
let formatter = DateComponentsFormatter()
|
||||
@@ -1168,6 +1341,8 @@ fileprivate func _debugPrint(_ items: Any) {
|
||||
|
||||
// Support for auto-rotate.
|
||||
class ConsoleViewController: UIViewController {
|
||||
|
||||
|
||||
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
|
||||
|
||||
// Cancel the panner console is being panned to allow for location manipulation.
|
||||
@@ -1235,40 +1410,77 @@ An object that allows you to manually request an increased display refresh rate
|
||||
|
||||
```
|
||||
// Example
|
||||
let request = FrameRateRequest(preferredFrameRate: 120,
|
||||
duration: 0.4)
|
||||
FrameRateRequest.shared.perform(duration: 0.5)
|
||||
request.perform()
|
||||
```
|
||||
*/
|
||||
class FrameRateRequest {
|
||||
@available(iOS 15, *)
|
||||
final class FrameRateRequest {
|
||||
|
||||
static let shared = FrameRateRequest()
|
||||
|
||||
lazy private var displayLink = CADisplayLink(target: self, selector: #selector(dummyFunction))
|
||||
|
||||
var isActive: Bool = false {
|
||||
private var requestIdentifiers: [UUID] = [] {
|
||||
didSet {
|
||||
guard #available(iOS 15, *) else { return }
|
||||
guard isActive != oldValue else { return }
|
||||
isActive = requestIdentifiers.count > 0
|
||||
}
|
||||
}
|
||||
|
||||
private var isActive: Bool = false {
|
||||
didSet {
|
||||
guard isActive != oldValue, UIScreen.main.maximumFramesPerSecond > 60 else { return }
|
||||
|
||||
if isActive {
|
||||
displayLink.add(to: .current, forMode: .common)
|
||||
} else {
|
||||
displayLink.remove(from: .current, forMode: .common)
|
||||
displayLink.invalidate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepares your frame rate request parameters.
|
||||
init(preferredFrameRate: Float = Float(UIScreen.main.maximumFramesPerSecond)) {
|
||||
if #available(iOS 15, *) {
|
||||
displayLink.preferredFrameRateRange = CAFrameRateRange(minimum: 30, maximum: Float(UIScreen.main.maximumFramesPerSecond), preferred: preferredFrameRate)
|
||||
}
|
||||
private init() {
|
||||
guard UIScreen.main.maximumFramesPerSecond > 60 else { return }
|
||||
|
||||
displayLink.preferredFrameRateRange = CAFrameRateRange(minimum: 90, maximum: Float(UIScreen.main.maximumFramesPerSecond), preferred: Float(UIScreen.main.maximumFramesPerSecond))
|
||||
|
||||
// Ensure the DisplayLink stops when the app enters the background, or else the system will shut high frame rate capabilities until the app is suspended and relaunched.
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground),
|
||||
name: UIApplication.willEnterForegroundNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackground),
|
||||
name: UIApplication.didEnterBackgroundNotification, object: nil)
|
||||
}
|
||||
|
||||
/// Perform frame rate request.
|
||||
func perform(duration: Double) {
|
||||
isActive = true
|
||||
public func perform(duration: Double) {
|
||||
|
||||
guard UIScreen.main.maximumFramesPerSecond > 60 else { return }
|
||||
|
||||
let id = UUID()
|
||||
|
||||
requestIdentifiers.append(id)
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + duration) { [self] in
|
||||
isActive = false
|
||||
requestIdentifiers = requestIdentifiers.filter { $0 != id }
|
||||
}
|
||||
}
|
||||
|
||||
public func activate(id: UUID) {
|
||||
requestIdentifiers.append(id)
|
||||
}
|
||||
|
||||
public func deactivate(id: UUID) {
|
||||
requestIdentifiers = requestIdentifiers.filter { $0 != id }
|
||||
}
|
||||
|
||||
@objc private func willEnterForeground() {
|
||||
if isActive {
|
||||
displayLink.add(to: .current, forMode: .common)
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func didEnterBackground() {
|
||||
if isActive {
|
||||
displayLink.invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +119,9 @@ class ResizeController {
|
||||
// Ensure initial autolayout is performed unanimated.
|
||||
LCManager.shared.consoleWindow?.layoutIfNeeded()
|
||||
|
||||
FrameRateRequest().perform(duration: 1.5)
|
||||
if #available(iOS 15, *) {
|
||||
FrameRateRequest.shared.perform(duration: 1.5)
|
||||
}
|
||||
|
||||
if isActive {
|
||||
|
||||
@@ -207,7 +209,7 @@ class ResizeController {
|
||||
static let kMinConsoleHeight: CGFloat = 108
|
||||
static let kMaxConsoleHeight: CGFloat = 346
|
||||
|
||||
let verticalPanner_frameRateRequest = FrameRateRequest()
|
||||
var verticalPanner_frameRateRequestID: UUID?
|
||||
|
||||
@objc func verticalPanner(recognizer: UIPanGestureRecognizer) {
|
||||
|
||||
@@ -218,7 +220,10 @@ class ResizeController {
|
||||
|
||||
switch recognizer.state {
|
||||
case .began:
|
||||
verticalPanner_frameRateRequest.isActive = true
|
||||
if #available(iOS 15, *) {
|
||||
verticalPanner_frameRateRequestID = UUID()
|
||||
FrameRateRequest.shared.activate(id: verticalPanner_frameRateRequestID!)
|
||||
}
|
||||
|
||||
initialHeight = LCManager.shared.consoleSize.height
|
||||
|
||||
@@ -251,9 +256,13 @@ class ResizeController {
|
||||
LCManager.shared.consoleView.center.y = consoleCenterPoint.y
|
||||
|
||||
case .ended, .cancelled:
|
||||
verticalPanner_frameRateRequest.isActive = false
|
||||
|
||||
FrameRateRequest().perform(duration: 0.4)
|
||||
|
||||
if #available(iOS 15, *), let id = verticalPanner_frameRateRequestID {
|
||||
verticalPanner_frameRateRequestID = nil
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
FrameRateRequest.shared.deactivate(id: id)
|
||||
}
|
||||
}
|
||||
|
||||
UIViewPropertyAnimator(duration: 0.4, dampingRatio: 0.7) {
|
||||
if LCManager.shared.consoleSize.height > maxHeight {
|
||||
@@ -284,7 +293,7 @@ class ResizeController {
|
||||
static let kMinConsoleWidth: CGFloat = 112
|
||||
static let kMaxConsoleWidth: CGFloat = [UIScreen.portraitSize.width, UIScreen.portraitSize.height].min()! - 56
|
||||
|
||||
let horizontalPanner_frameRateRequest = FrameRateRequest()
|
||||
var horizontalPanner_frameRateRequestID: UUID?
|
||||
|
||||
@objc func horizontalPanner(recognizer: UIPanGestureRecognizer) {
|
||||
|
||||
@@ -295,7 +304,10 @@ class ResizeController {
|
||||
|
||||
switch recognizer.state {
|
||||
case .began:
|
||||
horizontalPanner_frameRateRequest.isActive = true
|
||||
if #available(iOS 15, *) {
|
||||
horizontalPanner_frameRateRequestID = UUID()
|
||||
FrameRateRequest.shared.activate(id: horizontalPanner_frameRateRequestID!)
|
||||
}
|
||||
|
||||
initialWidth = LCManager.shared.consoleSize.width
|
||||
|
||||
@@ -328,9 +340,12 @@ class ResizeController {
|
||||
|
||||
case .ended, .cancelled:
|
||||
|
||||
horizontalPanner_frameRateRequest.isActive = false
|
||||
|
||||
FrameRateRequest().perform(duration: 0.4)
|
||||
if #available(iOS 15, *), let id = horizontalPanner_frameRateRequestID {
|
||||
horizontalPanner_frameRateRequestID = nil
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
FrameRateRequest.shared.deactivate(id: id)
|
||||
}
|
||||
}
|
||||
|
||||
UIViewPropertyAnimator(duration: 0.4, dampingRatio: 0.7) {
|
||||
if LCManager.shared.consoleSize.width > maxWidth {
|
||||
|
||||
Reference in New Issue
Block a user