Skip to content

Commit a49fd1d

Browse files
authored
fix notification macos glass border (#3699)
* in-meeting-notif message adjustment * kind of works * border stuff
1 parent a8abe3b commit a49fd1d

File tree

6 files changed

+74
-13
lines changed

6 files changed

+74
-13
lines changed

apps/desktop/src/contexts/listener.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,11 @@ const useHandleDetectEvents = (store: ListenerStore) => {
121121
}
122122

123123
const minutes = Math.round(payload.duration_secs / 60);
124-
const appName = payload.app.name;
125124

126125
void notificationCommands.showNotification({
127126
key: payload.key,
128127
title: "Meeting in progress?",
129-
message: `${appName} has been using the mic for ${minutes} min. Start listening?`,
128+
message: `Mic used for ${minutes} minutes. Start listening?`,
130129
timeout: { secs: 15, nanos: 0 },
131130
event_id: null,
132131
start_time: null,

crates/notification-macos/swift-lib/src/NotificationManager+Animation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ extension NotificationManager {
55
notification: NotificationInstance, screen: NSScreen, timeoutSeconds: Double
66
) {
77
let screenRect = screen.visibleFrame
8-
let finalX = screenRect.maxX - panelWidth() - Layout.rightMargin + Layout.buttonOverhang
8+
let finalX = screenRect.maxX - panelWidth() - Layout.rightMargin + buttonOverhang()
99
let y = notification.panel.frame.minY
1010

1111
notification.panel.setFrame(

crates/notification-macos/swift-lib/src/NotificationManager+Creation.swift

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
import Cocoa
22

33
extension NotificationManager {
4+
func isMacOS26() -> Bool {
5+
NSClassFromString("NSGlassEffectView") != nil
6+
}
7+
8+
func buttonOverhang() -> CGFloat {
9+
isMacOS26() ? 0 : Layout.buttonOverhang
10+
}
11+
412
func createPanel(screen: NSScreen? = nil, yPosition: CGFloat) -> NSPanel {
513
let targetScreen = screen ?? getTargetScreen() ?? NSScreen.main!
614
let screenRect = targetScreen.visibleFrame
@@ -21,7 +29,7 @@ extension NotificationManager {
2129
panel.hidesOnDeactivate = false
2230
panel.isOpaque = false
2331
panel.backgroundColor = .clear
24-
panel.hasShadow = true
32+
panel.hasShadow = !isMacOS26()
2533
panel.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary, .ignoresCycle]
2634
panel.isMovableByWindowBackground = false
2735
panel.alphaValue = 0
@@ -36,13 +44,21 @@ extension NotificationManager {
3644
frame: NSRect(x: 0, y: 0, width: panelWidth(), height: panelHeight()))
3745
v.wantsLayer = true
3846
v.layer?.backgroundColor = NSColor.clear.cgColor
47+
v.layer?.isOpaque = false
48+
if isMacOS26() {
49+
v.layer?.cornerRadius = Layout.cornerRadius
50+
v.layer?.masksToBounds = true
51+
if #available(macOS 11.0, *) {
52+
v.layer?.cornerCurve = .continuous
53+
}
54+
}
3955
v.autoresizingMask = [.width, .height]
4056
return v
4157
}
4258

4359
func createContainer(clickableView: ClickableView) -> NSView {
44-
let overhang = Layout.buttonOverhang
45-
let container = NSView(
60+
let overhang = buttonOverhang()
61+
let container = ShadowContainerView(
4662
frame: NSRect(
4763
x: overhang,
4864
y: 0,
@@ -53,6 +69,9 @@ extension NotificationManager {
5369
container.wantsLayer = true
5470
container.layer?.cornerRadius = Layout.cornerRadius
5571
container.layer?.masksToBounds = false
72+
if #available(macOS 11.0, *) {
73+
container.layer?.cornerCurve = .continuous
74+
}
5675
container.autoresizingMask = [.width, .height]
5776
container.layer?.shadowColor = NSColor.black.cgColor
5877
container.layer?.shadowOpacity = 0.22
@@ -62,17 +81,25 @@ extension NotificationManager {
6281
}
6382

6483
func createEffectView(container: NSView) -> (NSVisualEffectView, NotificationBackgroundView) {
84+
let isMacOS26 = isMacOS26()
85+
6586
let effectView = NSVisualEffectView(frame: container.bounds)
6687
effectView.material = .popover
6788
effectView.state = .active
68-
effectView.blendingMode = .behindWindow
89+
effectView.blendingMode = isMacOS26 ? .withinWindow : .behindWindow
6990
effectView.wantsLayer = true
7091
effectView.layer?.cornerRadius = Layout.cornerRadius
7192
effectView.layer?.masksToBounds = true
93+
if isMacOS26, #available(macOS 11.0, *) {
94+
effectView.layer?.cornerCurve = .continuous
95+
}
7296
effectView.autoresizingMask = [.width, .height]
7397

7498
let backgroundView = NotificationBackgroundView(frame: effectView.bounds)
7599
backgroundView.autoresizingMask = [.width, .height]
100+
if isMacOS26 {
101+
backgroundView.makeBackgroundOpaque()
102+
}
76103
effectView.addSubview(backgroundView, positioned: .below, relativeTo: nil)
77104

78105
container.addSubview(effectView)
@@ -106,7 +133,7 @@ extension NotificationManager {
106133
closeButton.translatesAutoresizingMaskIntoConstraints = false
107134
clickableView.addSubview(closeButton, positioned: .above, relativeTo: nil)
108135

109-
let buttonOffset = (CloseButtonConfig.size / 2) - 2
136+
let buttonOffset = isMacOS26() ? (CloseButtonConfig.size / 2) + 4 : (CloseButtonConfig.size / 2) - 2
110137
NSLayoutConstraint.activate([
111138
closeButton.centerYAnchor.constraint(equalTo: container.topAnchor, constant: buttonOffset),
112139
closeButton.centerXAnchor.constraint(

crates/notification-macos/swift-lib/src/NotificationManager+Layout.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ extension NotificationManager {
2525
func repositionNotifications(animated: Bool = true) {
2626
guard let screen = getTargetScreen() else { return }
2727
let screenRect = screen.visibleFrame
28-
let rightPosition = screenRect.maxX - panelWidth() - Layout.rightMargin + Layout.buttonOverhang
28+
let rightPosition = screenRect.maxX - panelWidth() - Layout.rightMargin + buttonOverhang()
2929

3030
let sorted = activeNotifications.values.sorted { $0.panel.frame.minY > $1.panel.frame.minY }
3131

32-
var currentY = screenRect.maxY - Layout.topMargin + Layout.buttonOverhang
32+
var currentY = screenRect.maxY - Layout.topMargin + buttonOverhang()
3333

3434
for notification in sorted {
3535
let height = notification.panel.frame.height
@@ -70,16 +70,16 @@ extension NotificationManager {
7070
occupiedHeight += notification.panel.frame.height + notificationSpacing
7171
}
7272

73-
let baseY = screenRect.maxY - panelHeight() - Layout.topMargin + Layout.buttonOverhang
73+
let baseY = screenRect.maxY - panelHeight() - Layout.topMargin + buttonOverhang()
7474
return baseY - occupiedHeight
7575
}
7676

7777
func panelWidth() -> CGFloat {
78-
Layout.notificationWidth + Layout.buttonOverhang
78+
Layout.notificationWidth + buttonOverhang()
7979
}
8080

8181
func panelHeight(expanded: Bool = false) -> CGFloat {
8282
let contentHeight = expanded ? Layout.expandedNotificationHeight : Layout.notificationHeight
83-
return contentHeight + Layout.buttonOverhang
83+
return contentHeight + buttonOverhang()
8484
}
8585
}

crates/notification-macos/swift-lib/src/NotificationManager+Lifecycle.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ extension NotificationManager {
2323

2424
clickableView.addSubview(container)
2525
panel.contentView = clickableView
26+
if isMacOS26() {
27+
panel.contentView?.wantsLayer = true
28+
panel.contentView?.layer?.cornerRadius = Layout.cornerRadius
29+
panel.contentView?.layer?.masksToBounds = true
30+
if #available(macOS 11.0, *) {
31+
panel.contentView?.layer?.cornerCurve = .continuous
32+
}
33+
}
2634

2735
setupContent(effectView: effectView, container: container, notification: notification)
2836

crates/notification-macos/swift-lib/src/NotificationViews.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
import Cocoa
22

3+
class ShadowContainerView: NSView {
4+
override func layout() {
5+
super.layout()
6+
let pathRect = bounds.insetBy(dx: 0.5, dy: 0.5)
7+
layer?.shadowPath = CGPath(
8+
roundedRect: pathRect,
9+
cornerWidth: Layout.cornerRadius,
10+
cornerHeight: Layout.cornerRadius,
11+
transform: nil
12+
)
13+
}
14+
}
15+
316
class NotificationBackgroundView: NSView {
417
let bgLayer = CALayer()
518
let borderLayer = CALayer()
@@ -18,6 +31,20 @@ class NotificationBackgroundView: NSView {
1831
}
1932
}
2033

34+
func makeBackgroundOpaque() {
35+
bgLayer.backgroundColor = NSColor(calibratedWhite: 0.92, alpha: 1.0).cgColor
36+
layer?.cornerRadius = Layout.cornerRadius
37+
bgLayer.cornerRadius = Layout.cornerRadius
38+
borderLayer.cornerRadius = Layout.cornerRadius
39+
borderLayer.borderWidth = 1.5
40+
borderLayer.borderColor = NSColor(calibratedWhite: 0.75, alpha: 0.5).cgColor
41+
if #available(macOS 11.0, *) {
42+
layer?.cornerCurve = .continuous
43+
bgLayer.cornerCurve = .continuous
44+
borderLayer.cornerCurve = .continuous
45+
}
46+
}
47+
2148
private var progressBarFullWidth: CGFloat {
2249
bounds.width - (Layout.progressBarInset * 2)
2350
}

0 commit comments

Comments
 (0)