Compare commits

..

21 Commits

Author SHA1 Message Date
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
Duraid Abdul ec386069a2 Update LCManager.swift 2021-08-27 14:04:56 -07:00
Duraid Abdul ab36ae5bb8 Update LCManager.swift
Fix keyboard avoidance, improve view states throughout interaction.
2021-08-27 12:39:48 -07:00
Duraid Abdul e6846048d0 Console hiding animation refinements 2021-08-27 01:58:06 -07:00
Duraid Abdul d6d9aad082 @available fix 2021-08-26 23:59:12 -07:00
Duraid Abdul 6723947fe6 Update LCManager.swift 2021-08-26 23:42:41 -07:00
Duraid Abdul 24a7a197b0 Hide Console Interaction
Added interaction and animations for hiding console away
2021-08-26 23:41:53 -07:00
3 changed files with 391 additions and 97 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
+384 -89
View File
@@ -5,8 +5,6 @@
// Copyright © 2021 Duraid Abdul. All rights reserved.
//
//#if canImport(UIKit)
import UIKit
import SwiftUI
@@ -48,6 +46,62 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
let defaultConsoleSize = CGSize(width: 228, height: 142)
lazy var borderView = UIView()
var lumaWidthAnchor: NSLayoutConstraint!
var lumaHeightAnchor: NSLayoutConstraint!
lazy var lumaView: LumaView = {
let lumaView = LumaView()
lumaView.foregroundView.backgroundColor = .black
lumaView.layer.cornerRadius = consoleView.layer.cornerRadius
consoleView.addSubview(lumaView)
lumaView.translatesAutoresizingMaskIntoConstraints = false
lumaWidthAnchor = lumaView.widthAnchor.constraint(equalTo: consoleView.widthAnchor)
lumaHeightAnchor = lumaView.heightAnchor.constraint(equalToConstant: consoleView.frame.size.height)
NSLayoutConstraint.activate([
lumaWidthAnchor,
lumaHeightAnchor,
lumaView.centerXAnchor.constraint(equalTo: consoleView.centerXAnchor),
lumaView.centerYAnchor.constraint(equalTo: consoleView.centerYAnchor)
])
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 {
@@ -106,20 +160,85 @@ 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 {
return [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,
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)]
// 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),
// 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)]
if consoleView.frame.minX <= 0 {
// Left edge endpoints.
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 + 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 {
// 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 - 28,
y: endpoints[0].y))
} else {
endpoints.append(CGPoint(x: UIScreen.portraitSize.width + consoleSize.width / 2 - 28,
y: endpoints[1].y))
}
}
return endpoints
} else {
return [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)]
// 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)]
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 + 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 {
// Right edge hiding endpoints.
if consoleView.center.y < (UIScreen.portraitSize.height - (temporaryKeyboardHeightValueTracker ?? 0)) / 2 {
endpoints.append(CGPoint(x: UIScreen.portraitSize.width + consoleSize.width / 2 - 28,
y: endpoints[0].y))
} else {
endpoints.append(CGPoint(x: UIScreen.portraitSize.width + consoleSize.width / 2 - 28,
y: endpoints[1].y))
}
}
return endpoints
}
}
@@ -129,21 +248,20 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
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.backgroundColor = .black
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.cornerCurve = .continuous
let borderView = UIView()
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
@@ -199,7 +317,8 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
circle.isUserInteractionEnabled = false
menuButton.addSubview(circle)
let ellipsisImage = UIImageView(image: UIImage(systemName: "ellipsis", withConfiguration: UIImage.SymbolConfiguration(pointSize: 17)))
let ellipsisImage = UIImageView(image: UIImage(systemName: "ellipsis",
withConfiguration: UIImage.SymbolConfiguration(pointSize: 17, weight: .medium)))
ellipsisImage.frame.size = circle.bounds.size
ellipsisImage.contentMode = .center
circle.addSubview(ellipsisImage)
@@ -209,6 +328,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)
}
@@ -217,6 +338,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 > UIScreen.portraitSize.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
@@ -235,11 +371,11 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
consoleWindow?.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 {
@@ -260,6 +396,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 {
@@ -303,6 +447,62 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
}
}
var grabberMode: Bool = false {
didSet {
guard oldValue != grabberMode else { return }
if grabberMode {
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
}.startAnimation()
lumaWidthAnchor.constant = -34
lumaHeightAnchor.constant = 96
UIViewPropertyAnimator(duration: 0.4, dampingRatio: 1) { [self] in
lumaView.layer.cornerRadius = 8
consoleView.layoutIfNeeded()
}.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
}.startAnimation()
UIViewPropertyAnimator(duration: 0.3, dampingRatio: 1) { [self] in
consoleTextView.alpha = 1
menuButton.alpha = 1
borderView.alpha = 1
}.startAnimation(afterDelay: 0.2)
UIViewPropertyAnimator(duration: 0.65, dampingRatio: 1) { [self] in
lumaView.foregroundView.alpha = 1
}.startAnimation()
consoleTextView.isUserInteractionEnabled = true
unhideButton.isHidden = true
}
}
}
/// Print items to the console view.
public func print(_ items: Any) {
if currentText == "" {
@@ -324,18 +524,25 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
// MARK: - Private
var temporaryKeyboardHeightValueTracker: CGFloat?
// MARK: Handle keyboard show/hide.
private var keyboardHeight: CGFloat? = nil {
didSet {
temporaryKeyboardHeightValueTracker = oldValue
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()
}
temporaryKeyboardHeightValueTracker = keyboardHeight
}
}
@@ -454,10 +661,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 {
@@ -493,22 +696,22 @@ 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()
}
})
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])
@@ -519,14 +722,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 = {
@@ -551,28 +754,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])])
@@ -592,6 +802,9 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
@objc func longPressAction(recognizer: UILongPressGestureRecognizer) {
switch recognizer.state {
case .began:
guard !grabberMode else { return }
feedbackGenerator.selectionChanged()
scrollLocked = false
@@ -599,17 +812,21 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
UIViewPropertyAnimator(duration: 0.4, dampingRatio: 1) { [self] in
consoleView.transform = .init(scaleX: 1.04, y: 1.04)
consoleTextView.alpha = 0.5
menuButton.alpha = 0.5
}.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
consoleTextView.alpha = 1
if !grabberMode {
consoleTextView.alpha = 1
menuButton.alpha = 1
}
}.startAnimation()
default: break
}
@@ -629,8 +846,16 @@ 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 {
grabberMode = false
} else {
grabberMode = true
}
case .ended, .cancelled:
@@ -649,27 +874,31 @@ 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.scrollLocked = !self.grabberMode
}
default: break
}
}
// Animate touch down.
func consolePiPTouchDown() {
UIViewPropertyAnimator(duration: 1, dampingRatio: 0.5) { [self] in
consoleView.transform = .init(scaleX: 0.96, y: 0.96)
}.startAnimation()
guard !grabberMode else { return }
UIViewPropertyAnimator(duration: 0.4, dampingRatio: 1) { [self] in
if !scrollLocked {
consoleView.backgroundColor = #colorLiteral(red: 0.1331297589, green: 0.1331297589, blue: 0.1331297589, alpha: 1)
}
UIViewPropertyAnimator(duration: 1.25, dampingRatio: 0.5) { [self] in
consoleView.transform = .init(scaleX: 0.95, y: 0.95)
}.startAnimation()
}
@@ -680,11 +909,10 @@ public class LCManager: NSObject, UIGestureRecognizerDelegate {
}.startAnimation()
UIViewPropertyAnimator(duration: 0.4, dampingRatio: 1) { [self] in
consoleTextView.alpha = 1
}.startAnimation()
UIViewPropertyAnimator(duration: 0.75, dampingRatio: 1) { [self] in
consoleView.backgroundColor = .black
if !grabberMode {
consoleTextView.alpha = 1
menuButton.alpha = 1
}
}.startAnimation()
}
@@ -697,15 +925,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
@@ -748,7 +970,7 @@ extension UIView {
let swizzledMethod = class_getInstanceMethod(UIView.self, #selector(swizzled_layoutSubviews)) else { return }
method_exchangeImplementations(originalMethod, swizzledMethod)
}
@objc func swizzled_layoutSubviews() {
swizzled_layoutSubviews()
@@ -773,7 +995,80 @@ extension UIWindow {
}
}
//#endif
class LumaView: UIView {
lazy var visualEffectView: UIView = {
Bundle(path: "/Sys" + "tem/Lib" + "rary/Private" + "Frameworks/Material" + "Kit." + "framework")!.load()
let Pill = NSClassFromString("MT" + "Luma" + "Dodge" + "Pill" + "View") as! UIView.Type
let pillView = Pill.init()
enum Style: Int {
case none = 0
case thin = 1
case gray = 2
case black = 3
case white = 4
}
enum BackgroundLuminance: Int {
case unknown = 0
case dark = 1
case light = 2
}
pillView.setValue(2, forKey: "style")
pillView.setValue(1, forKey: "background" + "Luminance")
pillView.perform(NSSelectorFromString("_" + "update" + "Style"))
addSubview(pillView)
pillView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
pillView.leadingAnchor.constraint(equalTo: leadingAnchor),
pillView.trailingAnchor.constraint(equalTo: trailingAnchor),
pillView.topAnchor.constraint(equalTo: topAnchor),
pillView.bottomAnchor.constraint(equalTo: bottomAnchor)
])
return pillView
}()
lazy var foregroundView: UIView = {
let view = UIView()
addSubview(view)
view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
view.leadingAnchor.constraint(equalTo: leadingAnchor),
view.trailingAnchor.constraint(equalTo: trailingAnchor),
view.topAnchor.constraint(equalTo: topAnchor),
view.bottomAnchor.constraint(equalTo: bottomAnchor)
])
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
let _ = visualEffectView
let _ = foregroundView
visualEffectView.isUserInteractionEnabled = false
foregroundView.isUserInteractionEnabled = false
layer.cornerCurve = .continuous
clipsToBounds = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class InvertedTextView: UITextView {
@@ -782,7 +1077,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 {
+5 -1
View File
@@ -170,7 +170,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()
@@ -236,6 +236,7 @@ class ResizeController {
}
}()
LCManager.shared.lumaHeightAnchor.constant = resolvedHeight
LCManager.shared.consoleSize.height = resolvedHeight
LCManager.shared.consoleView.center.y = consoleCenterPoint.y
@@ -243,9 +244,11 @@ class ResizeController {
UIViewPropertyAnimator(duration: 0.4, dampingRatio: 0.7) {
if LCManager.shared.consoleSize.height > maxHeight {
LCManager.shared.consoleSize.height = maxHeight
LCManager.shared.lumaHeightAnchor.constant = maxHeight
}
if LCManager.shared.consoleSize.height < minHeight {
LCManager.shared.consoleSize.height = minHeight
LCManager.shared.lumaHeightAnchor.constant = minHeight
}
LCManager.shared.consoleView.center.y = self.consoleCenterPoint.y
@@ -475,6 +478,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()