Improve animations and resizing again. Add option for animation speed.
This commit is contained in:
@@ -11,9 +11,11 @@ class ScreenManager: ObservableObject {
|
||||
|
||||
static let shared = ScreenManager()
|
||||
private let focusRetryDelay: TimeInterval = 0.01
|
||||
private let presetResizeFrameInterval: TimeInterval = 1.0 / 60.0
|
||||
|
||||
private(set) var windows: [String: NotchWindow] = [:]
|
||||
private(set) var viewModels: [String: NotchViewModel] = [:]
|
||||
private var presetResizeTimers: [String: Timer] = [:]
|
||||
|
||||
@AppStorage(NotchSettings.Keys.showOnAllDisplays)
|
||||
private var showOnAllDisplays = NotchSettings.Defaults.showOnAllDisplays
|
||||
@@ -140,10 +142,9 @@ class ScreenManager: ObservableObject {
|
||||
return
|
||||
}
|
||||
|
||||
withAnimation(vm.openAnimation) {
|
||||
vm.applySizePreset(preset, notifyWindowResize: false)
|
||||
}
|
||||
updateWindowFrame(for: screenUUID, centerHorizontally: true)
|
||||
let startSize = vm.notchSize
|
||||
let targetSize = vm.setStoredOpenSize(preset.size)
|
||||
animatePresetResize(for: screenUUID, from: startSize, to: targetSize, duration: vm.openAnimationDuration)
|
||||
}
|
||||
|
||||
// MARK: - Window creation
|
||||
@@ -236,10 +237,28 @@ class ScreenManager: ObservableObject {
|
||||
window: NotchWindow,
|
||||
centerHorizontally: Bool = false
|
||||
) {
|
||||
guard let vm = viewModels[screenUUID] else { return }
|
||||
let frame = targetWindowFrame(
|
||||
for: screenUUID,
|
||||
on: screen,
|
||||
window: window,
|
||||
centerHorizontally: centerHorizontally,
|
||||
contentSize: nil
|
||||
)
|
||||
guard !window.frame.equalTo(frame) else { return }
|
||||
window.setFrame(frame, display: false)
|
||||
}
|
||||
|
||||
private func targetWindowFrame(
|
||||
for screenUUID: String,
|
||||
on screen: NSScreen,
|
||||
window: NotchWindow,
|
||||
centerHorizontally: Bool,
|
||||
contentSize: CGSize?
|
||||
) -> NSRect {
|
||||
guard let vm = viewModels[screenUUID] else { return window.frame }
|
||||
|
||||
let shadowPadding: CGFloat = 20
|
||||
let openSize = vm.openNotchSize
|
||||
let openSize = contentSize ?? vm.openNotchSize
|
||||
let windowWidth = openSize.width + 40
|
||||
let windowHeight = openSize.height + shadowPadding
|
||||
let centeredX = screen.frame.origin.x + (screen.frame.width - windowWidth) / 2
|
||||
@@ -248,12 +267,87 @@ class ScreenManager: ObservableObject {
|
||||
? centeredX
|
||||
: min(max(window.frame.minX, screen.frame.minX), screen.frame.maxX - windowWidth)
|
||||
|
||||
let frame = NSRect(
|
||||
return NSRect(
|
||||
x: x,
|
||||
y: screen.frame.origin.y + screen.frame.height - windowHeight,
|
||||
width: windowWidth,
|
||||
height: windowHeight
|
||||
)
|
||||
}
|
||||
|
||||
private func animatePresetResize(
|
||||
for screenUUID: String,
|
||||
from startSize: CGSize,
|
||||
to targetSize: CGSize,
|
||||
duration: TimeInterval
|
||||
) {
|
||||
cancelPresetResize(for: screenUUID)
|
||||
|
||||
guard let vm = viewModels[screenUUID] else { return }
|
||||
guard startSize != targetSize else {
|
||||
vm.notchSize = targetSize
|
||||
updateWindowFrame(for: screenUUID, centerHorizontally: true)
|
||||
return
|
||||
}
|
||||
|
||||
vm.isPresetResizing = true
|
||||
let startTime = CACurrentMediaTime()
|
||||
let duration = max(duration, presetResizeFrameInterval)
|
||||
|
||||
let timer = Timer(timeInterval: presetResizeFrameInterval, repeats: true) { [weak self] timer in
|
||||
MainActor.assumeIsolated {
|
||||
guard let self, let vm = self.viewModels[screenUUID] else {
|
||||
timer.invalidate()
|
||||
return
|
||||
}
|
||||
|
||||
let elapsed = CACurrentMediaTime() - startTime
|
||||
let progress = min(1, elapsed / duration)
|
||||
let easedProgress = 0.5 - (cos(.pi * progress) / 2)
|
||||
let size = CGSize(
|
||||
width: startSize.width + ((targetSize.width - startSize.width) * easedProgress),
|
||||
height: startSize.height + ((targetSize.height - startSize.height) * easedProgress)
|
||||
)
|
||||
|
||||
vm.notchSize = size
|
||||
self.updateWindowFrame(for: screenUUID, contentSize: size, centerHorizontally: true)
|
||||
|
||||
if progress >= 1 {
|
||||
vm.notchSize = targetSize
|
||||
vm.isPresetResizing = false
|
||||
self.updateWindowFrame(for: screenUUID, contentSize: targetSize, centerHorizontally: true)
|
||||
self.presetResizeTimers[screenUUID] = nil
|
||||
timer.invalidate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
presetResizeTimers[screenUUID] = timer
|
||||
RunLoop.main.add(timer, forMode: .common)
|
||||
timer.fire()
|
||||
}
|
||||
|
||||
private func cancelPresetResize(for screenUUID: String) {
|
||||
presetResizeTimers[screenUUID]?.invalidate()
|
||||
presetResizeTimers[screenUUID] = nil
|
||||
viewModels[screenUUID]?.isPresetResizing = false
|
||||
}
|
||||
|
||||
private func updateWindowFrame(
|
||||
for screenUUID: String,
|
||||
contentSize: CGSize,
|
||||
centerHorizontally: Bool = false
|
||||
) {
|
||||
guard let screen = NSScreen.screens.first(where: { $0.displayUUID == screenUUID }),
|
||||
let window = windows[screenUUID] else { return }
|
||||
|
||||
let frame = targetWindowFrame(
|
||||
for: screenUUID,
|
||||
on: screen,
|
||||
window: window,
|
||||
centerHorizontally: centerHorizontally,
|
||||
contentSize: contentSize
|
||||
)
|
||||
guard !window.frame.equalTo(frame) else { return }
|
||||
window.setFrame(frame, display: false)
|
||||
}
|
||||
@@ -261,6 +355,10 @@ class ScreenManager: ObservableObject {
|
||||
// MARK: - Cleanup
|
||||
|
||||
private func cleanupAllWindows() {
|
||||
for (_, timer) in presetResizeTimers {
|
||||
timer.invalidate()
|
||||
}
|
||||
presetResizeTimers.removeAll()
|
||||
for (_, window) in windows {
|
||||
window.orderOut(nil)
|
||||
window.close()
|
||||
|
||||
Reference in New Issue
Block a user