Improve resizing with draggable and hotkeys
This commit is contained in:
@@ -28,6 +28,8 @@ struct ContentView: View {
|
||||
@AppStorage(NotchSettings.Keys.hoverSpringDamping) private var hoverSpringDamping = NotchSettings.Defaults.hoverSpringDamping
|
||||
|
||||
@State private var hoverTask: Task<Void, Never>?
|
||||
@State private var resizeStartSize: CGSize?
|
||||
@State private var resizeStartMouseLocation: CGPoint?
|
||||
|
||||
private var hoverAnimation: Animation {
|
||||
.interactiveSpring(response: hoverSpringResponse, dampingFraction: hoverSpringDamping)
|
||||
@@ -53,6 +55,11 @@ struct ContentView: View {
|
||||
.overlay(alignment: .top) {
|
||||
Rectangle().fill(.black).frame(height: 1)
|
||||
}
|
||||
.overlay(alignment: .bottomTrailing) {
|
||||
if vm.notchState == .open {
|
||||
resizeHandle
|
||||
}
|
||||
}
|
||||
.shadow(
|
||||
color: enableShadow ? Color.black.opacity(shadowOpacity) : .clear,
|
||||
radius: enableShadow ? shadowRadius : 0
|
||||
@@ -62,8 +69,8 @@ struct ContentView: View {
|
||||
.opacity(notchOpacity)
|
||||
.blur(radius: blurRadius)
|
||||
.animation(vm.notchState == .open ? vm.openAnimation : vm.closeAnimation, value: vm.notchState)
|
||||
.animation(vm.notchState == .open ? vm.openAnimation : vm.closeAnimation, value: vm.notchSize.width)
|
||||
.animation(vm.notchState == .open ? vm.openAnimation : vm.closeAnimation, value: vm.notchSize.height)
|
||||
.animation(sizeAnimation, value: vm.notchSize.width)
|
||||
.animation(sizeAnimation, value: vm.notchSize.height)
|
||||
.onHover { handleHover($0) }
|
||||
.onChange(of: vm.isCloseTransitionActive) { _, isClosing in
|
||||
if isClosing {
|
||||
@@ -74,6 +81,9 @@ struct ContentView: View {
|
||||
}
|
||||
.onDisappear {
|
||||
hoverTask?.cancel()
|
||||
resizeStartSize = nil
|
||||
resizeStartMouseLocation = nil
|
||||
vm.endInteractiveResize()
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
@@ -104,6 +114,47 @@ struct ContentView: View {
|
||||
.background(.black)
|
||||
}
|
||||
|
||||
private var resizeHandle: some View {
|
||||
ResizeHandleShape()
|
||||
.stroke(.white.opacity(0.32), style: StrokeStyle(lineWidth: 1.2, lineCap: .round))
|
||||
.frame(width: 16, height: 16)
|
||||
.padding(.trailing, 8)
|
||||
.padding(.bottom, 8)
|
||||
.contentShape(Rectangle().inset(by: -8))
|
||||
.gesture(resizeGesture)
|
||||
}
|
||||
|
||||
private var resizeGesture: some Gesture {
|
||||
DragGesture(minimumDistance: 0)
|
||||
.onChanged { value in
|
||||
if resizeStartSize == nil {
|
||||
resizeStartSize = vm.notchSize
|
||||
resizeStartMouseLocation = NSEvent.mouseLocation
|
||||
vm.beginInteractiveResize()
|
||||
}
|
||||
|
||||
guard let startSize = resizeStartSize,
|
||||
let startMouseLocation = resizeStartMouseLocation else { return }
|
||||
let currentMouseLocation = NSEvent.mouseLocation
|
||||
vm.resizeOpenNotch(
|
||||
to: CGSize(
|
||||
width: startSize.width + ((currentMouseLocation.x - startMouseLocation.x) * 2),
|
||||
height: startSize.height + (startMouseLocation.y - currentMouseLocation.y)
|
||||
)
|
||||
)
|
||||
}
|
||||
.onEnded { _ in
|
||||
resizeStartSize = nil
|
||||
resizeStartMouseLocation = nil
|
||||
vm.endInteractiveResize()
|
||||
}
|
||||
}
|
||||
|
||||
private var sizeAnimation: Animation? {
|
||||
guard !vm.isUserResizing else { return nil }
|
||||
return vm.notchState == .open ? vm.openAnimation : vm.closeAnimation
|
||||
}
|
||||
|
||||
/// Open layout: VStack with toolbar row on top, terminal in the middle,
|
||||
/// tab bar at the bottom. Every section has a black background.
|
||||
private var openContent: some View {
|
||||
@@ -187,3 +238,16 @@ struct ContentView: View {
|
||||
title.count <= 30 ? title : String(title.prefix(28)) + "…"
|
||||
}
|
||||
}
|
||||
|
||||
private struct ResizeHandleShape: Shape {
|
||||
func path(in rect: CGRect) -> Path {
|
||||
var path = Path()
|
||||
path.move(to: CGPoint(x: rect.maxX - 10, y: rect.maxY))
|
||||
path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY - 10))
|
||||
path.move(to: CGPoint(x: rect.maxX - 6, y: rect.maxY))
|
||||
path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY - 6))
|
||||
path.move(to: CGPoint(x: rect.maxX - 2, y: rect.maxY))
|
||||
path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY - 2))
|
||||
return path
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user