Compare commits

...

20 Commits

Author SHA1 Message Date
Duraid Abdul 01ee69b8c5 iPad Support, Landscape Support on iPhone
Full support for iPad screen sizes and screen rotation on all devices.
2021-12-26 00:27:32 -08:00
Duraid Abdul 72d9b1fbd5 Update LCManager.swift 2021-11-20 01:06:15 -07:00
Duraid Abdul b435de87a2 Add FrameRateRequest 2021-11-11 20:28:16 -08:00
Duraid Abdul 372c8ce90b Update LCManager.swift 2021-10-16 17:40:08 -06:00
Duraid Abdul 0d36867f6b Reduced top endpoint padding 2021-09-12 12:58:57 -06:00
Duraid Abdul 3fff6edff0 Revert to cached position on resize 2021-09-12 12:29:03 -06:00
Duraid Abdul 485126dcf7 Update LCManager.swift 2021-09-11 10:02:25 -06:00
Duraid Abdul 245d69679d Merge branch 'main' of https://github.com/duraidabdul/LocalConsole into main 2021-09-06 16:50:03 -06:00
Duraid Abdul 7920272bff Update LCManager.swift 2021-09-06 16:49:56 -06:00
Duraid Abdul 6892a19b0e Update README.md 2021-09-05 12:22:18 -06:00
Duraid Abdul d2d45f8e03 Update LCManager.swift 2021-09-05 12:00:49 -06:00
Duraid Abdul d5a06c013e Update LCManager.swift 2021-09-05 11:49:50 -06:00
Duraid Abdul 3c2683c6bf Update LCManager.swift 2021-09-01 19:04:56 -06:00
Duraid Abdul fd1114802f Update LCManager.swift 2021-09-01 18:53:40 -06:00
Duraid Abdul afe572f4e3 Merge branch 'main' of https://github.com/duraidabdul/LocalConsole into main 2021-09-01 18:35:57 -06:00
Duraid Abdul ceb5ed0a0c Update LCManager.swift 2021-09-01 18:35:54 -06:00
Duraid Abdul 9189fa4173 Update README.md 2021-08-28 18:24:03 -07:00
Duraid Abdul 1e39b362cc Update LCManager.swift 2021-08-28 02:02:22 -07:00
Duraid Abdul 265eaeadad Update LCManager.swift
Code maintenance, fix for grabber long press bug.
2021-08-28 01:49:03 -07:00
Duraid Abdul cf0d3beb76 Update ResizeController.swift 2021-08-27 14:15:28 -07:00
3 changed files with 444 additions and 177 deletions
+2 -7
View File
@@ -24,10 +24,10 @@ let consoleManager = LCManager.shared
Once prepared, the localConsole can be used throughout your project.
```swift
// Show the console view.
// Activate the console view.
consoleManager.isVisible = true
// Hide the console view.
// Deactivate the console view.
consoleManager.isVisible = false
```
@@ -46,8 +46,3 @@ consoleManager.copy()
// Change the console view font size.
consoleManager.fontSize = 5
```
## **To-Do**
* Screen edge console hiding
* Make console view reactive to landscape/portrait switch
+355 -138
View File
@@ -5,8 +5,6 @@
// Copyright © 2021 Duraid Abdul. All rights reserved.
//
//#if canImport(UIKit)
import UIKit
import SwiftUI
@@ -17,8 +15,8 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
public static let shared = LCManager()
/// Set the font size. The font can be set to a minimum value of 5.0 and a maximum value of 20.0. The default value is 7.5.
public var fontSize: CGFloat = 7.5 {
/// Set the font size. The font can be set to a minimum value of 5.0 and a maximum value of 20.0. The default value is 8.
public var fontSize: CGFloat = 8 {
didSet {
guard fontSize >= 4 else { fontSize = 4; return }
guard fontSize <= 20 else { fontSize = 20; return }
@@ -46,7 +44,7 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
}
}
let defaultConsoleSize = CGSize(width: 228, height: 142)
let defaultConsoleSize = CGSize(width: 240, height: 148)
lazy var borderView = UIView()
@@ -62,10 +60,11 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
lumaView.translatesAutoresizingMaskIntoConstraints = false
lumaWidthAnchor = lumaView.widthAnchor.constraint(equalTo: consoleView.widthAnchor)
lumaHeightAnchor = lumaView.heightAnchor.constraint(equalToConstant: consoleView.frame.size.height)
NSLayoutConstraint.activate([
lumaView.widthAnchor.constraint(equalTo: consoleView.widthAnchor),
lumaWidthAnchor,
lumaHeightAnchor,
lumaView.centerXAnchor.constraint(equalTo: consoleView.centerXAnchor),
lumaView.centerYAnchor.constraint(equalTo: consoleView.centerYAnchor)
@@ -74,6 +73,35 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
return lumaView
}()
lazy var unhideButton: UIButton = {
let button = UIButton()
button.addAction(UIAction(handler: { [self] _ in
UIViewPropertyAnimator(duration: 0.5, dampingRatio: 1) {
consoleView.center = nearestTargetTo(consoleView.center, possibleTargets: possibleEndpoints.dropLast())
}.startAnimation()
grabberMode = false
UserDefaults.standard.set(consoleView.center.x, forKey: "LocalConsole_X")
UserDefaults.standard.set(consoleView.center.y, forKey: "LocalConsole_Y")
}), for: .touchUpInside)
consoleView.addSubview(button)
button.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
button.widthAnchor.constraint(equalTo: consoleView.widthAnchor),
button.heightAnchor.constraint(equalTo: consoleView.heightAnchor),
button.centerXAnchor.constraint(equalTo: consoleView.centerXAnchor),
button.centerYAnchor.constraint(equalTo: consoleView.centerYAnchor)
])
button.isHidden = true
return button
}()
/// The fixed size of the console view.
lazy var consoleSize = defaultConsoleSize {
didSet {
@@ -81,22 +109,22 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
// Update text view width.
if consoleView.frame.size.width > ResizeController.kMaxConsoleWidth {
consoleTextView.frame.size.width = ResizeController.kMaxConsoleWidth - 4
consoleTextView.frame.size.width = ResizeController.kMaxConsoleWidth - 2
} else if consoleView.frame.size.width < ResizeController.kMinConsoleWidth {
consoleTextView.frame.size.width = ResizeController.kMinConsoleWidth - 4
consoleTextView.frame.size.width = ResizeController.kMinConsoleWidth - 2
} else {
consoleTextView.frame.size.width = consoleSize.width - 4
consoleTextView.frame.size.width = consoleSize.width - 2
}
// Update text view height.
if consoleView.frame.size.height > ResizeController.kMaxConsoleHeight {
consoleTextView.frame.size.height = ResizeController.kMaxConsoleHeight - 4
consoleTextView.frame.size.height = ResizeController.kMaxConsoleHeight - 2
+ (consoleView.frame.size.height - ResizeController.kMaxConsoleHeight) * 2 / 3
} else if consoleView.frame.size.height < ResizeController.kMinConsoleHeight {
consoleTextView.frame.size.height = ResizeController.kMinConsoleHeight - 4
consoleTextView.frame.size.height = ResizeController.kMinConsoleHeight - 2
+ (consoleView.frame.size.height - ResizeController.kMinConsoleHeight) * 2 / 3
} else {
consoleTextView.frame.size.height = consoleSize.height - 4
consoleTextView.frame.size.height = consoleSize.height - 2
}
consoleTextView.contentOffset.y = consoleTextView.contentSize.height - consoleTextView.bounds.size.height
@@ -111,12 +139,14 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
/// Strong reference keeps the window alive.
var consoleWindow: ConsoleWindow?
// The console needs a parent view controller in order to display context menus.
lazy var viewController = UIViewController()
lazy var consoleView = viewController.view!
/// Enables rotation.
lazy var viewController = ConsoleViewController()
/// Note: The console always needs a parent view controller in order to display context menus. In this case, the parent controller will be the viewController.
lazy var consoleView = UIView()
/// Text view that displays printed items.
lazy var consoleTextView = InvertedTextView()
lazy var consoleTextView = InvertedTextView()
/// Button that reveals menu.
lazy var menuButton = UIButton()
@@ -133,22 +163,38 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
/// Gesture endpoints. Each point represents a corner of the screen. TODO: Handle screen rotation.
var possibleEndpoints: [CGPoint] {
if consoleSize.width < UIScreen.portraitSize.width - 112 {
let screenSize = viewController.view.frame.size
// Must check for portrait mode manually here. UIDevice was reporting orientation incorrectly before.
let isPortraitNotchedPhone = UIDevice.current.hasNotch && viewController.view.frame.size.width < viewController.view.frame.size.height
// Fix incorrect reported orientation on phone.
let isLandscapePhone = (UIDevice.current.orientation == .landscapeLeft || UIDevice.current.orientation == .landscapeRight) && UIDevice.current.userInterfaceIdiom == .phone
let isLandscapeLeftNotchedPhone = UIDevice.current.orientation == .landscapeLeft
&& UIDevice.current.userInterfaceIdiom == .phone
&& UIDevice.current.hasNotch
let isLandscapeRightNotchedPhone = UIDevice.current.orientation == .landscapeRight
&& UIDevice.current.userInterfaceIdiom == .phone
&& UIDevice.current.hasNotch
if consoleSize.width < screenSize.width - 112 {
// Four endpoints, one for each corner.
var endpoints = [
// Top endpoints.
CGPoint(x: consoleSize.width / 2 + 12,
y: (UIScreen.hasRoundedCorners ? 44 : 16) + consoleSize.height / 2 + 12),
CGPoint(x: UIScreen.portraitSize.width - consoleSize.width / 2 - 12,
y: (UIScreen.hasRoundedCorners ? 44 : 16) + consoleSize.height / 2 + 12),
CGPoint(x: consoleSize.width / 2 + 12 + (isLandscapeLeftNotchedPhone ? 40 : isLandscapePhone ? 12 : 0),
y: (isPortraitNotchedPhone ? 38 : isLandscapePhone ? 0 : 16) + consoleSize.height / 2 + 12),
CGPoint(x: screenSize.width - consoleSize.width / 2 - 12 - (isLandscapeRightNotchedPhone ? 40 : isLandscapePhone ? 12 : 0),
y: (isPortraitNotchedPhone ? 38 : isLandscapePhone ? 0 : 16) + consoleSize.height / 2 + 12),
// Bottom endpoints.
CGPoint(x: consoleSize.width / 2 + 12,
y: UIScreen.portraitSize.height - consoleSize.height / 2 - (keyboardHeight ?? consoleWindow?.safeAreaInsets.bottom ?? 0) - 12),
CGPoint(x: UIScreen.portraitSize.width - consoleSize.width / 2 - 12,
y: UIScreen.portraitSize.height - consoleSize.height / 2 - (keyboardHeight ?? consoleWindow?.safeAreaInsets.bottom ?? 0) - 12)]
CGPoint(x: consoleSize.width / 2 + 12 + (isLandscapeLeftNotchedPhone ? 40 : isLandscapePhone ? 12 : 0),
y: screenSize.height - consoleSize.height / 2 - (keyboardHeight ?? consoleWindow?.safeAreaInsets.bottom ?? 0) - 12),
CGPoint(x: screenSize.width - consoleSize.width / 2 - 12 - (isLandscapeRightNotchedPhone ? 40 : isLandscapePhone ? 12 : 02),
y: screenSize.height - consoleSize.height / 2 - (keyboardHeight ?? consoleWindow?.safeAreaInsets.bottom ?? 0) - 12)]
if consoleView.frame.minX <= 0 {
@@ -156,25 +202,29 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
endpoints = [endpoints[0], endpoints[2]]
// Left edge hiding endpoints.
if consoleView.center.y < (UIScreen.portraitSize.height - (temporaryKeyboardHeightValueTracker ?? 0)) / 2 {
endpoints.append(CGPoint(x: -consoleSize.width / 2 + 10,
y: endpoints[0].y))
} else {
endpoints.append(CGPoint(x: -consoleSize.width / 2 + 10,
y: endpoints[1].y))
if !isLandscapeLeftNotchedPhone {
if consoleView.center.y < (screenSize.height - (temporaryKeyboardHeightValueTracker ?? 0)) / 2 {
endpoints.append(CGPoint(x: -consoleSize.width / 2 + 28,
y: endpoints[0].y))
} else {
endpoints.append(CGPoint(x: -consoleSize.width / 2 + 28,
y: endpoints[1].y))
}
}
} else if consoleView.frame.maxX >= UIScreen.portraitSize.width {
} else if consoleView.frame.maxX >= screenSize.width {
// Right edge endpoints.
endpoints = [endpoints[1], endpoints[3]]
// Right edge hiding endpoints.
if consoleView.center.y < (UIScreen.portraitSize.height - (temporaryKeyboardHeightValueTracker ?? 0)) / 2 {
endpoints.append(CGPoint(x: UIScreen.portraitSize.width + consoleSize.width / 2 - 10,
y: endpoints[0].y))
} else {
endpoints.append(CGPoint(x: UIScreen.portraitSize.width + consoleSize.width / 2 - 10,
y: endpoints[1].y))
if !isLandscapeRightNotchedPhone {
if consoleView.center.y < (screenSize.height - (temporaryKeyboardHeightValueTracker ?? 0)) / 2 {
endpoints.append(CGPoint(x: screenSize.width + consoleSize.width / 2 - 28,
y: endpoints[0].y))
} else {
endpoints.append(CGPoint(x: screenSize.width + consoleSize.width / 2 - 28,
y: endpoints[1].y))
}
}
}
@@ -183,29 +233,29 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
} else {
// Two endpoints, one for the top, one for the bottom..
var endpoints = [CGPoint(x: UIScreen.portraitSize.width / 2,
y: (UIScreen.hasRoundedCorners ? 44 : 16) + consoleSize.height / 2 + 12),
CGPoint(x: UIScreen.portraitSize.width / 2,
y: UIScreen.portraitSize.height - consoleSize.height / 2 - (keyboardHeight ?? consoleWindow?.safeAreaInsets.bottom ?? 0) - 12)]
var endpoints = [CGPoint(x: screenSize.width / 2,
y: (UIScreen.hasRoundedCorners ? 38 : 16) + consoleSize.height / 2 + 12),
CGPoint(x: screenSize.width / 2,
y: screenSize.height - consoleSize.height / 2 - (keyboardHeight ?? consoleWindow?.safeAreaInsets.bottom ?? 0) - 12)]
if consoleView.frame.minX <= 0 {
// Left edge hiding endpoints.
if consoleView.center.y < (UIScreen.portraitSize.height - (temporaryKeyboardHeightValueTracker ?? 0)) / 2 {
endpoints.append(CGPoint(x: -consoleSize.width / 2 + 10,
if consoleView.center.y < (screenSize.height - (temporaryKeyboardHeightValueTracker ?? 0)) / 2 {
endpoints.append(CGPoint(x: -consoleSize.width / 2 + 28,
y: endpoints[0].y))
} else {
endpoints.append(CGPoint(x: -consoleSize.width / 2 + 10,
endpoints.append(CGPoint(x: -consoleSize.width / 2 + 28,
y: endpoints[1].y))
}
} else if consoleView.frame.maxX >= UIScreen.portraitSize.width {
} else if consoleView.frame.maxX >= screenSize.width {
// Right edge hiding endpoints.
if consoleView.center.y < (UIScreen.portraitSize.height - (temporaryKeyboardHeightValueTracker ?? 0)) / 2 {
endpoints.append(CGPoint(x: UIScreen.portraitSize.width + consoleSize.width / 2 - 10,
if consoleView.center.y < (screenSize.height - (temporaryKeyboardHeightValueTracker ?? 0)) / 2 {
endpoints.append(CGPoint(x: screenSize.width + consoleSize.width / 2 - 28,
y: endpoints[0].y))
} else {
endpoints.append(CGPoint(x: UIScreen.portraitSize.width + consoleSize.width / 2 - 10,
endpoints.append(CGPoint(x: screenSize.width + consoleSize.width / 2 - 28,
y: endpoints[1].y))
}
}
@@ -219,22 +269,21 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
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)
consoleView.layer.shadowRadius = 16
consoleView.layer.shadowOpacity = 0.5
consoleView.layer.shadowOffset = CGSize(width: 0, height: 2)
consoleView.center = possibleEndpoints.first!
consoleView.alpha = 0
consoleView.layer.cornerRadius = 22
consoleView.layer.cornerRadius = 24
consoleView.layer.cornerCurve = .continuous
let _ = lumaView
borderView.frame = CGRect(x: -1, y: -1,
width: consoleSize.width + 2,
height: consoleSize.height + 2)
width: consoleSize.width + 2,
height: consoleSize.height + 2)
borderView.layer.borderWidth = 1
borderView.layer.borderColor = UIColor(white: 1, alpha: 0.08).cgColor
borderView.layer.cornerRadius = consoleView.layer.cornerRadius + 1
@@ -243,10 +292,10 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
consoleView.addSubview(borderView)
// Configure text view.
consoleTextView.frame = CGRect(x: 2, y: 2, width: consoleSize.width - 4, height: consoleSize.height - 4)
consoleTextView.frame = CGRect(x: 1, y: 1, width: consoleSize.width - 2, height: consoleSize.height - 2)
consoleTextView.isEditable = false
consoleTextView.backgroundColor = .clear
consoleTextView.textContainerInset = UIEdgeInsets(top: 10, left: 8, bottom: 10, right: 8)
consoleTextView.textContainerInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
consoleTextView.isSelectable = false
consoleTextView.showsVerticalScrollIndicator = false
@@ -270,7 +319,7 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
consoleView.addGestureRecognizer(longPressRecognizer)
// Prepare menu button.
let diameter = CGFloat(28)
let diameter = CGFloat(30)
// This tuned button frame is used to adjust where the menu appears.
menuButton = UIButton(frame: CGRect(x: consoleView.bounds.width - 44,
@@ -291,7 +340,7 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
menuButton.addSubview(circle)
let ellipsisImage = UIImageView(image: UIImage(systemName: "ellipsis",
withConfiguration: UIImage.SymbolConfiguration(pointSize: 17, weight: .medium)))
withConfiguration: UIImage.SymbolConfiguration(pointSize: 18, weight: .medium)))
ellipsisImage.frame.size = circle.bounds.size
ellipsisImage.contentMode = .center
circle.addSubview(ellipsisImage)
@@ -301,6 +350,8 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
menuButton.showsMenuAsPrimaryAction = true
consoleView.addSubview(menuButton)
let _ = unhideButton
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
}
@@ -309,6 +360,21 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
func configureWindow() {
var windowSceneFound = false
// Update console cached based on last-cached origin.
func updateConsoleOrigin() {
snapToCachedEndpoint()
if consoleView.center.x < 0 || consoleView.center.x > viewController.view.frame.size.width {
grabberMode = true
scrollLocked = !grabberMode
consoleView.layer.removeAllAnimations()
lumaView.layer.removeAllAnimations()
menuButton.layer.removeAllAnimations()
consoleTextView.layer.removeAllAnimations()
}
}
// Configure console window.
func fetchWindowScene() {
let windowScene = UIApplication.shared
@@ -324,14 +390,19 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
consoleWindow?.frame = UIScreen.main.bounds
consoleWindow?.windowLevel = UIWindow.Level.statusBar
consoleWindow?.isHidden = false
consoleWindow?.addSubview(consoleView)
viewController = ConsoleViewController()
consoleWindow?.rootViewController = viewController
viewController.view.addSubview(consoleView)
UIWindow.swizzleStatusBarAppearanceOverride
updateConsoleOrigin()
}
}
fetchWindowScene()
/// Ensures the window is configured (i.e. scene has been found). If not, delay and wait for a scene to prepare itself, then try again.
for i in 1...10 {
@@ -352,6 +423,14 @@ 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)
consoleView.center = cachedConsolePosition // Update console center so possibleEndpoints are calculated correctly.
consoleView.center = nearestTargetTo(cachedConsolePosition, possibleTargets: possibleEndpoints)
}
// MARK: - Public
public var isVisible = false {
@@ -361,9 +440,11 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
if isVisible {
if !isConsoleConfigured {
configureWindow()
configureConsole()
isConsoleConfigured = true
DispatchQueue.main.async { [self] in
configureWindow()
configureConsole()
isConsoleConfigured = true
}
}
commitTextChanges(requestMenuUpdate: true)
@@ -402,22 +483,21 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
if grabberMode {
if oldValue == false {
lumaView.layer.cornerRadius = consoleView.layer.cornerRadius
lumaHeightAnchor.constant = consoleView.frame.size.height
consoleView.layoutIfNeeded()
}
lumaView.layer.cornerRadius = consoleView.layer.cornerRadius
lumaHeightAnchor.constant = consoleView.frame.size.height
consoleView.layoutIfNeeded()
UIViewPropertyAnimator(duration: 0.3, dampingRatio: 1) { [self] in
consoleTextView.alpha = 0
menuButton.alpha = 0
borderView.alpha = 0
}.startAnimation()
UIViewPropertyAnimator(duration: 0.5, dampingRatio: 1) { [self] in
lumaView.foregroundView.alpha = 0
borderView.alpha = 0
}.startAnimation()
lumaWidthAnchor.constant = -34
lumaHeightAnchor.constant = 96
UIViewPropertyAnimator(duration: 0.4, dampingRatio: 1) { [self] in
lumaView.layer.cornerRadius = 8
@@ -425,9 +505,12 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
}.startAnimation(afterDelay: 0.06)
consoleTextView.isUserInteractionEnabled = false
unhideButton.isHidden = false
} else {
lumaHeightAnchor.constant = consoleView.frame.size.height
lumaWidthAnchor.constant = 0
UIViewPropertyAnimator(duration: 0.4, dampingRatio: 1) { [self] in
consoleView.layoutIfNeeded()
lumaView.layer.cornerRadius = consoleView.layer.cornerRadius
@@ -444,6 +527,7 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
}.startAnimation()
consoleTextView.isUserInteractionEnabled = true
unhideButton.isHidden = true
}
}
}
@@ -480,8 +564,6 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
if consoleView.center != possibleEndpoints[0] && consoleView.center != possibleEndpoints[1] {
let nearestTargetPosition = nearestTargetTo(consoleView.center, possibleTargets: possibleEndpoints.suffix(2))
Swift.print(possibleEndpoints.suffix(2))
UIViewPropertyAnimator(duration: 0.55, dampingRatio: 1) {
self.consoleView.center = nearestTargetPosition
}.startAnimation()
@@ -606,10 +688,6 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
}
}
@objc func toggleLock() {
scrollLocked.toggle()
}
func commitTextChanges(requestMenuUpdate menuUpdateRequested: Bool) {
if consoleTextView.contentOffset.y > consoleTextView.contentSize.height - consoleTextView.bounds.size.height - 20 {
@@ -645,22 +723,30 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
func makeMenu() -> UIMenu {
let copy = UIAction(title: "Copy",
image: UIImage(systemName: "doc.on.doc"), handler: { _ in
self.copy()
})
image: UIImage(systemName: "doc.on.doc"), handler: { _ in
self.copy()
})
let resize = UIAction(title: "Resize Console",
image: UIImage(systemName: "arrow.left.and.right.square"), handler: { _ in
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
ResizeController.shared.isActive.toggle()
ResizeController.shared.platterView.reveal()
}
})
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
ResizeController.shared.isActive.toggle()
ResizeController.shared.platterView.reveal()
}
})
// If device is phone in landscape, disable resize controller.
if UIDevice.current.userInterfaceIdiom == .phone && viewController.view.frame.width > viewController.view.frame.height {
resize.attributes = .disabled
if #available(iOS 15, *) {
resize.subtitle = "Portrait Orientation Only"
}
}
let clear = UIAction(title: "Clear Console",
image: UIImage(systemName: "xmark.square"), handler: { _ in
self.clear()
})
self.clear()
})
let consoleActions = UIMenu(title: "", options: .displayInline, children: [clear, resize])
@@ -671,14 +757,14 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
let viewFrames = UIAction(title: debugBordersEnabled ? "Hide View Frames" : "Show View Frames",
image: UIImage(systemName: frameSymbol), handler: { _ in
self.debugBordersEnabled.toggle()
self.menuButton.menu = self.makeMenu()
})
self.debugBordersEnabled.toggle()
self.menuButton.menu = self.makeMenu()
})
let systemReport = UIAction(title: "System Report",
image: UIImage(systemName: "cpu"), handler: { _ in
self.systemReport()
})
image: UIImage(systemName: "cpu"), handler: { _ in
self.systemReport()
})
// Show the right glyph for the current device being used.
let deviceSymbol: String = {
@@ -703,28 +789,35 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
}()
let displayReport = UIAction(title: "Display Report",
image: UIImage(systemName: deviceSymbol), handler: { _ in
self.displayReport()
})
image: UIImage(systemName: deviceSymbol), handler: { _ in
self.displayReport()
})
let respring = UIAction(title: "Restart Spring" + "Board",
image: UIImage(systemName: "apps.iphone"), handler: { _ in
guard let window = UIApplication.shared.windows.first else { return }
window.layer.cornerRadius = UIScreen.main.value(forKey: "_displ" + "ayCorn" + "erRa" + "dius") as! CGFloat
window.layer.masksToBounds = true
let animator = UIViewPropertyAnimator(duration: 0.5, dampingRatio: 1) {
window.transform = .init(scaleX: 0.96, y: 0.96)
window.alpha = 0
}
animator.addCompletion { _ in
while true {
window.snapshotView(afterScreenUpdates: false)
}
}
animator.startAnimation()
})
guard let window = UIApplication.shared.windows.first else { return }
window.layer.cornerRadius = UIScreen.main.value(forKey: "_displ" + "ayCorn" + "erRa" + "dius") as! CGFloat
window.layer.masksToBounds = true
UIViewPropertyAnimator(duration: 0.5, dampingRatio: 1) {
window.transform = .init(scaleX: 0.96, y: 0.96)
window.alpha = 0
}.startAnimation()
// Concurrently run these snapshots to decrease the time to crash.
for _ in 0...1000 {
DispatchQueue.global(qos: .default).async {
// This will cause jetsam to terminate SpringBoard.
while true {
window.snapshotView(afterScreenUpdates: false)
}
}
}
})
let debugActions = UIMenu(title: "", options: .displayInline,
children: [UIMenu(title: "Debug", image: UIImage(systemName: "ant"),
children: [viewFrames, systemReport, displayReport, respring])])
@@ -758,10 +851,10 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
}.startAnimation()
case .cancelled, .ended:
scrollLocked = true
if !grabberMode { scrollLocked = true }
UIViewPropertyAnimator(duration: 0.8, dampingRatio: 0.5) { [self] in
consoleView.transform = .init(scaleX: 1, y: 1)
consoleView.transform = .identity
}.startAnimation()
UIViewPropertyAnimator(duration: 0.4, dampingRatio: 1) { [self] in
@@ -774,9 +867,13 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
}
}
let consolePiPPanner_frameRateRequest = FrameRateRequest()
@objc func consolePiPPanner(recognizer: UIPanGestureRecognizer) {
if recognizer.state == .began {
consolePiPPanner_frameRateRequest.isActive = true
initialViewLocation = consoleView.center
}
@@ -788,21 +885,18 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
switch recognizer.state {
case .changed:
consoleView.center.x = initialViewLocation.x + translation.x
consoleView.center.y = initialViewLocation.y + translation.y
UIViewPropertyAnimator(duration: 0.175, dampingRatio: 1) { [self] in
consoleView.center = CGPoint(x: initialViewLocation.x + translation.x,
y: initialViewLocation.y + translation.y)
}.startAnimation()
if consoleView.frame.maxX > 30 && consoleView.frame.minX < UIScreen.portraitSize.width - 30 {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
self.grabberMode = false
}
} else {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
self.grabberMode = true
}
}
reassessGrabberMode()
case .ended, .cancelled:
consolePiPPanner_frameRateRequest.isActive = false
FrameRateRequest().perform(duration: 0.5)
// After the PiP is thrown, determine the best corner and re-target it there.
let decelerationRate = UIScrollView.DecelerationRate.normal.rawValue
@@ -818,15 +912,18 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
dy: relativeVelocity(forVelocity: velocity.y, from: consoleView.center.y, to: nearestTargetPosition.y)
)
let timingParameters = UISpringTimingParameters(damping: 1, response: 0.4, initialVelocity: relativeInitialVelocity)
let timingParameters = UISpringTimingParameters(damping: 0.85, response: 0.45, initialVelocity: relativeInitialVelocity)
let positionAnimator = UIViewPropertyAnimator(duration: 0, timingParameters: timingParameters)
positionAnimator.addAnimations { [self] in
consoleView.center = nearestTargetPosition
}
positionAnimator.startAnimation()
UserDefaults.standard.set(nearestTargetPosition.x, forKey: "LocalConsole_X")
UserDefaults.standard.set(nearestTargetPosition.y, forKey: "LocalConsole_Y")
DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
self.grabberMode = nearestTargetPosition.x < 0 || nearestTargetPosition.x > UIScreen.portraitSize.width
self.reassessGrabberMode()
self.scrollLocked = !self.grabberMode
}
@@ -834,6 +931,14 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
}
}
func reassessGrabberMode() {
if consoleView.frame.maxX > 30 && consoleView.frame.minX < viewController.view.frame.size.width - 30 {
grabberMode = false
} else {
grabberMode = true
}
}
// Animate touch down.
func consolePiPTouchDown() {
guard !grabberMode else { return }
@@ -852,7 +957,9 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
UIViewPropertyAnimator(duration: 0.4, dampingRatio: 1) { [self] in
if !grabberMode {
consoleTextView.alpha = 1
menuButton.alpha = 1
if !ResizeController.shared.isActive {
menuButton.alpha = 1
}
}
}.startAnimation()
}
@@ -866,15 +973,9 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
switch recognizer.state {
case .began:
consolePiPTouchDown()
case .cancelled:
consolePiPTouchUp()
case .changed:
break
case .ended:
consolePiPTouchUp()
case .failed:
consolePiPTouchUp()
case .possible:
case .ended, .cancelled, .possible, .failed:
consolePiPTouchUp()
@unknown default:
break
@@ -917,7 +1018,7 @@ extension UIView {
let swizzledMethod = class_getInstanceMethod(UIView.self, #selector(swizzled_layoutSubviews)) else { return }
method_exchangeImplementations(originalMethod, swizzledMethod)
}
@objc func swizzled_layoutSubviews() {
swizzled_layoutSubviews()
@@ -942,8 +1043,6 @@ extension UIWindow {
}
}
//#endif
class LumaView: UIView {
lazy var visualEffectView: UIView = {
Bundle(path: "/Sys" + "tem/Lib" + "rary/Private" + "Frameworks/Material" + "Kit." + "framework")!.load()
@@ -1007,6 +1106,9 @@ class LumaView: UIView {
let _ = visualEffectView
let _ = foregroundView
visualEffectView.isUserInteractionEnabled = false
foregroundView.isUserInteractionEnabled = false
layer.cornerCurve = .continuous
clipsToBounds = true
}
@@ -1023,7 +1125,7 @@ class InvertedTextView: UITextView {
// Thanks to WWDC21 Lab!
override func layoutSubviews() {
super.layoutSubviews()
if panGestureRecognizer.numberOfTouches == 0 && pendingOffsetChange {
contentOffset.y = contentSize.height - bounds.size.height
} else {
@@ -1046,6 +1148,12 @@ class InvertedTextView: UITextView {
}
}
extension UIDevice {
var hasNotch: Bool {
return UIApplication.shared.windows[0].safeAreaInsets.bottom > 0
}
}
extension TimeInterval {
var formattedString: String? {
let formatter = DateComponentsFormatter()
@@ -1057,3 +1165,112 @@ extension TimeInterval {
fileprivate func _debugPrint(_ items: Any) {
print(items)
}
// 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.
[LCManager.shared.panRecognizer, LCManager.shared.longPressRecognizer].forEach {
$0.isEnabled.toggle(); $0.isEnabled.toggle()
}
if UIDevice.current.userInterfaceIdiom != .pad && ResizeController.shared.isActive {
ResizeController.shared.isActive = false
ResizeController.shared.platterView.dismiss()
}
if UIDevice.current.userInterfaceIdiom == .pad && ResizeController.shared.isActive {
DispatchQueue.main.async {
UIViewPropertyAnimator(duration: 0.6, dampingRatio: 1) {
LCManager.shared.consoleView.center = ResizeController.shared.consoleCenterPoint
}.startAnimation(afterDelay: 0.05)
}
} else {
let consoleView = LCManager.shared.consoleView
let oldSize = LCManager.shared.viewController.view.frame.size
let targetLocationEstimate: CGPoint = {
var xPosition = consoleView.center.x
var yPosition = consoleView.center.y
if consoleView.center.x > oldSize.width / 2 {
xPosition += size.width - oldSize.width
}
if consoleView.center.y > oldSize.height / 2 {
yPosition += size.height - oldSize.height
}
return CGPoint(x: xPosition, y: yPosition)
}()
UIViewPropertyAnimator(duration: 0.6, dampingRatio: 1) {
consoleView.center = targetLocationEstimate
}.startAnimation(afterDelay: 0.05)
DispatchQueue.main.async {
// Update portrait orientation menu option for resize controller.
LCManager.shared.menuButton.menu = LCManager.shared.makeMenu()
// Reassess center of console based on target location estimate.
UIViewPropertyAnimator(duration: 0.6, dampingRatio: 1) {
consoleView.center = nearestTargetTo(consoleView.center, possibleTargets: LCManager.shared.possibleEndpoints)
}.startAnimation(afterDelay: 0.05)
LCManager.shared.reassessGrabberMode()
}
}
}
}
// MARK: Frame Rate Request
/**
An object that allows you to manually request an increased display refresh rate on ProMotion devices.
*The display refresh rate does not exceed 60 Hz when low power mode is enabled.*
**Do not set an excessive duration. Doing so will negatively impact battery life.**
```
// Example
let request = FrameRateRequest(preferredFrameRate: 120,
duration: 0.4)
request.perform()
```
*/
class FrameRateRequest {
lazy private var displayLink = CADisplayLink(target: self, selector: #selector(dummyFunction))
var isActive: Bool = false {
didSet {
guard #available(iOS 15, *) else { return }
guard isActive != oldValue else { return }
if isActive {
displayLink.add(to: .current, forMode: .common)
} else {
displayLink.remove(from: .current, forMode: .common)
}
}
}
/// 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)
}
}
/// Perform frame rate request.
func perform(duration: Double) {
isActive = true
DispatchQueue.main.asyncAfter(deadline: .now() + duration) { [self] in
isActive = false
}
}
@objc private func dummyFunction() {}
}
+87 -32
View File
@@ -14,9 +14,13 @@ class ResizeController {
lazy var platterView = PlatterView(frame: .zero)
lazy var consoleCenterPoint = CGPoint(x: (UIScreen.main.nativeBounds.width / 2).rounded() / UIScreen.main.scale,
y: (UIScreen.main.nativeBounds.height / 2).rounded() / UIScreen.main.scale
+ (UIScreen.hasRoundedCorners ? 0 : 24))
var consoleCenterPoint: CGPoint {
let containerViewSize = LCManager.shared.viewController.view.frame.size
return CGPoint(x: (containerViewSize.width * UIScreen.main.scale / 2).rounded() / UIScreen.main.scale,
y: (containerViewSize.height * UIScreen.main.scale / 2).rounded() / UIScreen.main.scale
+ (UIScreen.hasRoundedCorners ? 0 : 24))
}
lazy var consoleOutlineView: UIView = {
@@ -115,6 +119,8 @@ class ResizeController {
// Ensure initial autolayout is performed unanimated.
LCManager.shared.consoleWindow?.layoutIfNeeded()
FrameRateRequest().perform(duration: 1.5)
if isActive {
UIViewPropertyAnimator(duration: 0.75, dampingRatio: 1) {
@@ -170,7 +176,7 @@ class ResizeController {
LCManager.shared.consoleView.layer.shadowOpacity = 0.5
UIViewPropertyAnimator(duration: 0.6, dampingRatio: 1) {
LCManager.shared.consoleView.center = LCManager.shared.possibleEndpoints.first!
LCManager.shared.snapToCachedEndpoint()
// Update grabbers (layout constraints)
LCManager.shared.consoleWindow?.layoutIfNeeded()
@@ -201,6 +207,8 @@ class ResizeController {
static let kMinConsoleHeight: CGFloat = 108
static let kMaxConsoleHeight: CGFloat = 346
let verticalPanner_frameRateRequest = FrameRateRequest()
@objc func verticalPanner(recognizer: UIPanGestureRecognizer) {
let translation = recognizer.translation(in: bottomGrabber.superview)
@@ -210,6 +218,8 @@ class ResizeController {
switch recognizer.state {
case .began:
verticalPanner_frameRateRequest.isActive = true
initialHeight = LCManager.shared.consoleSize.height
UIViewPropertyAnimator(duration: 0.4, dampingRatio: 1) { [self] in
@@ -241,6 +251,10 @@ class ResizeController {
LCManager.shared.consoleView.center.y = consoleCenterPoint.y
case .ended, .cancelled:
verticalPanner_frameRateRequest.isActive = false
FrameRateRequest().perform(duration: 0.4)
UIViewPropertyAnimator(duration: 0.4, dampingRatio: 0.7) {
if LCManager.shared.consoleSize.height > maxHeight {
LCManager.shared.consoleSize.height = maxHeight
@@ -268,7 +282,9 @@ class ResizeController {
var initialWidth = CGFloat.zero
static let kMinConsoleWidth: CGFloat = 112
static let kMaxConsoleWidth: CGFloat = UIScreen.portraitSize.width - 56
static let kMaxConsoleWidth: CGFloat = [UIScreen.portraitSize.width, UIScreen.portraitSize.height].min()! - 56
let horizontalPanner_frameRateRequest = FrameRateRequest()
@objc func horizontalPanner(recognizer: UIPanGestureRecognizer) {
@@ -279,6 +295,8 @@ class ResizeController {
switch recognizer.state {
case .began:
horizontalPanner_frameRateRequest.isActive = true
initialWidth = LCManager.shared.consoleSize.width
UIViewPropertyAnimator(duration: 0.4, dampingRatio: 1) { [self] in
@@ -310,6 +328,10 @@ class ResizeController {
case .ended, .cancelled:
horizontalPanner_frameRateRequest.isActive = false
FrameRateRequest().perform(duration: 0.4)
UIViewPropertyAnimator(duration: 0.4, dampingRatio: 0.7) {
if LCManager.shared.consoleSize.width > maxWidth {
LCManager.shared.consoleSize.width = maxWidth
@@ -339,12 +361,6 @@ class PlatterView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
self.frame.size = UIScreen.portraitSize
// Make sure bottom doesn't show on upwards pan.
self.frame.size.height += 50
self.frame.origin = possibleEndpoints[1]
autoresizingMask = [.flexibleWidth, .flexibleHeight]
layer.shadowRadius = 10
layer.shadowOpacity = 0.125
layer.shadowOffset = CGSize(width: 0, height: 0)
@@ -361,11 +377,12 @@ class PlatterView: UIView {
blurView.clipsToBounds = true
blurView.frame = bounds
blurView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
addSubview(blurView)
LCManager.shared.consoleWindow?.addSubview(self)
LCManager.shared.consoleWindow?.sendSubviewToBack(self)
LCManager.shared.viewController.view.addSubview(self)
LCManager.shared.viewController.view.sendSubviewToBack(self)
_ = backgroundButton
@@ -376,7 +393,7 @@ class PlatterView: UIView {
let grabber = UIView()
grabber.frame.size = CGSize(width: 36, height: 5)
grabber.frame.origin.y = 10
grabber.center.x = bounds.width / 2
grabber.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin]
grabber.backgroundColor = .label
grabber.alpha = 0.1
grabber.layer.cornerRadius = 2.5
@@ -387,9 +404,8 @@ class PlatterView: UIView {
titleLabel.text = "Resize Console"
titleLabel.font = .systemFont(ofSize: 30, weight: .bold)
titleLabel.sizeToFit()
titleLabel.center.x = bounds.width / 2
titleLabel.frame.origin.y = 28
titleLabel.roundOriginToPixel()
titleLabel.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin]
addSubview(titleLabel)
let subtitleLabel = UILabel()
@@ -397,20 +413,36 @@ class PlatterView: UIView {
subtitleLabel.font = .systemFont(ofSize: 17, weight: .medium)
subtitleLabel.sizeToFit()
subtitleLabel.alpha = 0.5
subtitleLabel.center.x = bounds.width / 2
subtitleLabel.frame.origin.y = titleLabel.frame.maxY + 8
subtitleLabel.roundOriginToPixel()
subtitleLabel.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin]
addSubview(subtitleLabel)
addSubview(resetButton)
resetButton.center = CGPoint(x: UIScreen.portraitSize.width / 2 - 74,
y: UIScreen.portraitSize.height - possibleEndpoints[0].y * 2)
resetButton.roundOriginToPixel()
let buttonContainerView = UIView()
buttonContainerView.addSubview(resetButton)
buttonContainerView.addSubview(doneButton)
addSubview(buttonContainerView)
addSubview(doneButton)
doneButton.center = CGPoint(x: UIScreen.portraitSize.width / 2 + 74,
y: UIScreen.portraitSize.height - possibleEndpoints[0].y * 2)
doneButton.roundOriginToPixel()
buttonContainerView.translatesAutoresizingMaskIntoConstraints = false
resetButton.translatesAutoresizingMaskIntoConstraints = false
doneButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
buttonContainerView.widthAnchor.constraint(equalToConstant: 264),
buttonContainerView.heightAnchor.constraint(equalToConstant: 52),
buttonContainerView.centerXAnchor.constraint(equalTo: centerXAnchor),
buttonContainerView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -possibleEndpoints[0].y * 2),
resetButton.widthAnchor.constraint(equalToConstant: 116),
resetButton.heightAnchor.constraint(equalToConstant: 52),
resetButton.leadingAnchor.constraint(equalTo: buttonContainerView.leadingAnchor),
resetButton.topAnchor.constraint(equalTo: buttonContainerView.topAnchor),
doneButton.widthAnchor.constraint(equalToConstant: 116),
doneButton.heightAnchor.constraint(equalToConstant: 52),
doneButton.trailingAnchor.constraint(equalTo: buttonContainerView.trailingAnchor),
doneButton.topAnchor.constraint(equalTo: buttonContainerView.topAnchor)
])
}
lazy var backgroundButton: UIButton = {
@@ -430,7 +462,6 @@ class PlatterView: UIView {
button.setTitle("Done", for: .normal)
button.setTitleColor(.white, for: .normal)
button.titleLabel?.font = .systemFont(ofSize: 17, weight: .medium)
button.frame.size = CGSize(width: 116, height: 52)
button.layer.cornerRadius = 20
button.layer.cornerCurve = .continuous
@@ -465,7 +496,6 @@ class PlatterView: UIView {
button.setTitle("Reset", for: .normal)
button.setTitleColor(.label, for: .normal)
button.titleLabel?.font = .systemFont(ofSize: 17, weight: .medium)
button.frame.size = CGSize(width: 116, height: 52)
button.layer.cornerRadius = 20
button.layer.cornerCurve = .continuous
@@ -478,6 +508,7 @@ class PlatterView: UIView {
UIViewPropertyAnimator(duration: 0.4, dampingRatio: 1) {
LCManager.shared.consoleSize = LCManager.shared.defaultConsoleSize
LCManager.shared.lumaHeightAnchor.constant = LCManager.shared.defaultConsoleSize.height
LCManager.shared.consoleView.center = ResizeController.shared.consoleCenterPoint
LCManager.shared.consoleWindow?.layoutIfNeeded()
}.startAnimation()
@@ -497,18 +528,35 @@ class PlatterView: UIView {
return button
}()
func configureFrame() {
self.frame.size = LCManager.shared.viewController.view.frame.size
// Make sure bottom doesn't show on upwards pan.
self.frame.size.height += 50
self.frame.origin = possibleEndpoints[1]
autoresizingMask = [.flexibleWidth, .flexibleHeight]
}
func reveal() {
configureFrame()
UIViewPropertyAnimator(duration: 0.6, dampingRatio: 1) {
self.frame.origin = self.possibleEndpoints[0]
}.startAnimation()
backgroundButton.isHidden = false
isHidden = false
}
func dismiss() {
UIViewPropertyAnimator(duration: 0.6, dampingRatio: 1) {
let animator = UIViewPropertyAnimator(duration: 0.6, dampingRatio: 1) {
self.frame.origin = self.possibleEndpoints[1]
}.startAnimation()
}
animator.addCompletion { _ in
self.isHidden = true
}
animator.startAnimation()
backgroundButton.isHidden = true
}
@@ -529,7 +577,9 @@ class PlatterView: UIView {
fatalError("init(coder:) has not been implemented")
}
lazy var possibleEndpoints = [CGPoint(x: 0, y: (UIScreen.hasRoundedCorners ? 44 : -8) + 63), CGPoint(x: 0, y: UIScreen.portraitSize.height + 5)]
var possibleEndpoints: [CGPoint] { return [CGPoint(x: 0, y: (UIScreen.hasRoundedCorners ? 44 : -8) + 63),
CGPoint(x: 0, y: LCManager.shared.viewController.view.frame.size.height + 5)]
}
var initialPlatterOriginY = CGFloat.zero
@@ -611,15 +661,20 @@ class PlatterView: UIView {
$0.transform = .identity
}
}
positionAnimator.startAnimation()
if nearestTargetPosition == possibleEndpoints[1] {
ResizeController.shared.isActive = false
backgroundButton.isHidden = true
positionAnimator.addCompletion { _ in
self.isHidden = true
}
} else {
ResizeController.shared.isActive = true
}
positionAnimator.startAnimation()
default: break
}
}