Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a1275a7f49 | |||
| e08d439d2b | |||
| da9d78f559 | |||
| 50e4ce4e03 | |||
| ae73be37b4 |
@@ -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.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -867,12 +889,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 +919,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
|
||||
@@ -1134,7 +1163,7 @@ class InvertedTextView: UITextView {
|
||||
|
||||
var pendingOffsetChange = false
|
||||
|
||||
// Thanks to WWDC21 Lab!
|
||||
// Thanks to WWDC21 UIKit Lab!
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
@@ -1166,6 +1195,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()
|
||||
@@ -1249,40 +1286,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