UIFix: Window Shadows and Notch Shadows

This commit is contained in:
Hariharan Mudaliar 2025-11-26 23:23:49 +05:30
commit 3bba53c583
4 changed files with 68 additions and 17 deletions

View file

@ -126,6 +126,20 @@ struct ContentView: View {
}
return cornerRadiusInsets
}
private var currentShadowPadding: CGFloat {
notchShadowPaddingValue(isMinimalistic: enableMinimalisticUI)
}
private var currentNotchShape: NotchShape {
let topRadius = (vm.notchState == .open && Defaults[.cornerRadiusScaling])
? activeCornerRadiusInsets.opened.top
: activeCornerRadiusInsets.closed.top
let bottomRadius = (vm.notchState == .open && Defaults[.cornerRadiusScaling])
? activeCornerRadiusInsets.opened.bottom
: activeCornerRadiusInsets.closed.bottom
return NotchShape(topCornerRadius: topRadius, bottomCornerRadius: bottomRadius)
}
var body: some View {
let interactionsEnabled = !lockScreenManager.isLocked
@ -139,16 +153,20 @@ struct ContentView: View {
)
.padding([.horizontal, .bottom], vm.notchState == .open ? 12 : 0)
.background(.black)
.mask {
((vm.notchState == .open) && Defaults[.cornerRadiusScaling])
? NotchShape(topCornerRadius: activeCornerRadiusInsets.opened.top, bottomCornerRadius: activeCornerRadiusInsets.opened.bottom)
.drawingGroup()
: NotchShape(topCornerRadius: activeCornerRadiusInsets.closed.top, bottomCornerRadius: activeCornerRadiusInsets.closed.bottom)
.drawingGroup()
}
.padding(.bottom, vm.notchState == .open && Defaults[.extendHoverArea] ? 0 : (vm.effectiveClosedNotchHeight == 0)
? zeroHeightHoverPadding
: 0
.clipShape(currentNotchShape)
.compositingGroup()
.shadow(
color: ((vm.notchState == .open || isHovering) && Defaults[.enableShadow])
? .black.opacity(0.6)
: .clear,
radius: Defaults[.cornerRadiusScaling] ? 10 : 5
)
.padding(.bottom,
currentShadowPadding + (
vm.notchState == .open && Defaults[.extendHoverArea]
? 0
: (vm.effectiveClosedNotchHeight == 0 ? zeroHeightHoverPadding : 0)
)
)
mainLayout
@ -280,7 +298,11 @@ struct ContentView: View {
// .keyboardShortcut("E", modifiers: .command)
}
}
.frame(maxWidth: dynamicNotchSize.width, maxHeight: dynamicNotchSize.height, alignment: .top)
.frame(
maxWidth: dynamicNotchSize.width,
maxHeight: dynamicNotchSize.height + currentShadowPadding,
alignment: .top
)
.animation(dynamicNotchResizeAnimation, value: dynamicNotchSize)
.animation(.easeInOut(duration: 0.4), value: coordinator.currentView)
.environmentObject(privacyManager)
@ -291,7 +313,6 @@ struct ContentView: View {
vm.shouldRecheckHover.toggle()
}
}
.shadow(color: ((vm.notchState == .open || isHovering) && Defaults[.enableShadow]) ? .black.opacity(0.6) : .clear, radius: Defaults[.cornerRadiusScaling] ? 10 : 5)
.background(dragDetector)
.environmentObject(vm)
.environmentObject(webcamManager)

View file

@ -278,11 +278,15 @@ class AppDelegate: NSObject, NSApplicationDelegate {
// Use minimalistic or normal size based on settings, then adjust for stats layout
let baseSize = Defaults[.enableMinimalisticUI] ? minimalisticOpenNotchSize : openNotchSize
return statsAdjustedNotchSize(
let adjustedContentSize = statsAdjustedNotchSize(
from: baseSize,
isStatsTabActive: coordinator.currentView == .stats,
secondRowProgress: coordinator.statsSecondRowExpansion
)
return addShadowPadding(
to: adjustedContentSize,
isMinimalistic: Defaults[.enableMinimalisticUI]
)
}
func ensureWindowSize(_ size: CGSize, animated: Bool, force: Bool = false) {

View file

@ -84,7 +84,11 @@ class DynamicIslandViewModel: NSObject, ObservableObject {
self.notchSize = updatedTarget
}
if let delegate = AppDelegate.shared {
delegate.ensureWindowSize(updatedTarget, animated: true, force: false)
delegate.ensureWindowSize(
addShadowPadding(to: updatedTarget, isMinimalistic: Defaults[.enableMinimalisticUI]),
animated: true,
force: false
)
}
}
.store(in: &cancellables)
@ -106,7 +110,11 @@ class DynamicIslandViewModel: NSObject, ObservableObject {
self.notchSize = updatedTarget
}
if let delegate = AppDelegate.shared {
delegate.ensureWindowSize(updatedTarget, animated: true, force: false)
delegate.ensureWindowSize(
addShadowPadding(to: updatedTarget, isMinimalistic: Defaults[.enableMinimalisticUI]),
animated: true,
force: false
)
}
}
.store(in: &cancellables)
@ -123,7 +131,11 @@ class DynamicIslandViewModel: NSObject, ObservableObject {
self.notchSize = updatedTarget
}
if let delegate = AppDelegate.shared {
delegate.ensureWindowSize(updatedTarget, animated: false, force: false)
delegate.ensureWindowSize(
addShadowPadding(to: updatedTarget, isMinimalistic: Defaults[.enableMinimalisticUI]),
animated: false,
force: false
)
}
}
.store(in: &cancellables)
@ -184,7 +196,11 @@ class DynamicIslandViewModel: NSObject, ObservableObject {
let applyWindowResize: () -> Void = {
guard let delegate = AppDelegate.shared else { return }
delegate.ensureWindowSize(targetSize, animated: false, force: true)
delegate.ensureWindowSize(
addShadowPadding(to: targetSize, isMinimalistic: Defaults[.enableMinimalisticUI]),
animated: false,
force: true
)
}
if Thread.isMainThread {

View file

@ -19,6 +19,8 @@ private let minimalisticBaseOpenNotchSize: CGSize = .init(width: 420, height: 18
private let minimalisticLyricsExtraHeight: CGFloat = 40
let statsSecondRowContentHeight: CGFloat = 120
let statsGridSpacingHeight: CGFloat = 12
let notchShadowPaddingStandard: CGFloat = 18
let notchShadowPaddingMinimalistic: CGFloat = 12
@MainActor
var minimalisticOpenNotchSize: CGSize {
@ -71,6 +73,14 @@ func statsAdjustedNotchSize(
return adjustedSize
}
func notchShadowPaddingValue(isMinimalistic: Bool) -> CGFloat {
isMinimalistic ? notchShadowPaddingMinimalistic : notchShadowPaddingStandard
}
func addShadowPadding(to size: CGSize, isMinimalistic: Bool) -> CGSize {
CGSize(width: size.width, height: size.height + notchShadowPaddingValue(isMinimalistic: isMinimalistic))
}
enum MusicPlayerImageSizes {
static let cornerRadiusInset: (opened: CGFloat, closed: CGFloat) = (opened: 13.0, closed: 4.0)
static let size = (opened: CGSize(width: 90, height: 90), closed: CGSize(width: 20, height: 20))