Skip to content

Commit fab9d7c

Browse files
committed
feat: new look for tahoe and liquid glass (closes #4658)
1 parent 4aec2aa commit fab9d7c

File tree

12 files changed

+130
-230
lines changed

12 files changed

+130
-230
lines changed

src/api-wrappers/HelperExtensions.swift

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -203,27 +203,9 @@ extension NSTextField {
203203
}
204204

205205
extension NSImage {
206-
func cgImage(maxSize: NSSize) -> CGImage {
207-
// some images like NSRunningApp.icon are from icns. They hosts multiple representations and it's hard to know the highest resolution
208-
// by setting a maxSize, the returned CGImage will be the biggest it can under that maxSize
209-
let ctx = CGContext(
210-
data: nil,
211-
width: Int(maxSize.width),
212-
height: Int(maxSize.height),
213-
bitsPerComponent: 8,
214-
bytesPerRow: 0,
215-
space: CGColorSpaceCreateDeviceRGB(),
216-
bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue
217-
)!
218-
NSGraphicsContext.current = NSGraphicsContext(cgContext: ctx, flipped: false)
219-
self.draw(
220-
in: CGRect(origin: .zero, size: maxSize),
221-
from: .zero,
222-
operation: .copy,
223-
fraction: 1.0
224-
)
225-
NSGraphicsContext.current = nil
226-
return ctx.makeImage()!
206+
func appIconFixedSize(_ size: NSSize) -> CGImage? {
207+
var rect = NSRect(origin: .zero, size: size)
208+
return cgImage(forProposedRect: &rect, context: nil, hints: nil)
227209
}
228210

229211
// NSImage(named) caches/reuses NSImage objects; we force separate instances of images by using copy()

src/logic/Appearance.swift

Lines changed: 51 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -3,57 +3,54 @@ import Cocoa
33
class Appearance {
44
// size
55
static var hideThumbnails = Bool(false)
6-
static var windowPadding = CGFloat(18)
7-
static var windowCornerRadius = CGFloat(23)
8-
static var cellCornerRadius = CGFloat(10)
9-
static var edgeInsetsSize = CGFloat(5)
10-
static var maxWidthOnScreen = CGFloat(0.8)
11-
static var rowsCount = CGFloat(0)
12-
static var iconSize = CGFloat(0)
13-
static var fontHeight = CGFloat(0)
14-
static var windowMinWidthInRow = CGFloat(0)
15-
static var windowMaxWidthInRow = CGFloat(0)
6+
static var windowPadding = CGFloat(1000)
7+
static var windowCornerRadius = CGFloat(1000)
8+
static var cellCornerRadius = CGFloat(1000)
9+
static var edgeInsetsSize = CGFloat(1000)
10+
static var maxWidthOnScreen = CGFloat(1000)
11+
static var rowsCount = CGFloat(1000)
12+
static var iconSize = CGFloat(1000)
13+
static var fontHeight = CGFloat(1000)
14+
static var windowMinWidthInRow = CGFloat(1000)
15+
static var windowMaxWidthInRow = CGFloat(1000)
16+
1617
// size: constants
1718
static let maxHeightOnScreen = CGFloat(0.8)
1819
static let interCellPadding = CGFloat(1)
1920
static let intraCellPadding = CGFloat(5)
2021
static let appIconLabelSpacing = CGFloat(2)
2122

2223
// theme
23-
static var fontColor = NSColor.white
24-
static var indicatedIconShadowColor: NSColor? = .darkGray
25-
static var titleShadowColor: NSColor? = .darkGray
26-
static var highlightMaterial = NSVisualEffectView.Material.selection
27-
static var material = NSVisualEffectView.Material.dark
28-
static var imageShadowColor: NSColor? = .gray // for icon, thumbnail and windowless images
29-
static var highlightFocusedAlphaValue = 1.0
30-
static var highlightHoveredAlphaValue = 0.8
31-
static var highlightFocusedBackgroundColor = NSColor.black.withAlphaComponent(0.5)
32-
static var highlightHoveredBackgroundColor = NSColor.black.withAlphaComponent(0.3)
33-
static var highlightFocusedBorderColor = NSColor.clear
34-
static var highlightHoveredBorderColor = NSColor.clear
35-
static var highlightBorderShadowColor = NSColor.clear
36-
static var highlightBorderWidth = CGFloat(0)
37-
static var enablePanelShadow = false
24+
static var fontColor = NSColor.red
25+
static var imagesShadowColor = NSColor.red // for icon, thumbnail and windowless images
26+
static var material = NSVisualEffectView.Material.ultraDark
27+
static var highlightBorderWidth = CGFloat(3)
28+
29+
// theme: constants
30+
static let enablePanelShadow = true
31+
static let highlightFocusedBackgroundColor = NSColor.systemAccentColor.withAlphaComponent(0.2)
32+
static let highlightHoveredBackgroundColor = NSColor.systemAccentColor.withAlphaComponent(0.1)
33+
static let highlightFocusedBorderColor = NSColor.systemAccentColor
34+
static let highlightHoveredBorderColor = NSColor.systemAccentColor.withAlphaComponent(0.7)
35+
3836

3937
// derived
4038
static var font: NSFont {
4139
if #available(macOS 26.0, *) {
42-
return NSFont.systemFont(ofSize: fontHeight, weight: .medium)
40+
return NSFont.systemFont(ofSize: fontHeight, weight: .semibold)
4341
}
4442
return NSFont.systemFont(ofSize: fontHeight)
4543
}
4644

4745
private static var currentStyle: AppearanceStylePreference { Preferences.appearanceStyle }
4846
private static var currentSize: AppearanceSizePreference { Preferences.appearanceSize }
49-
private static var currentTheme: AppearanceThemePreference {
47+
static var currentTheme: AppearanceThemePreference {
5048
if Preferences.appearanceTheme == .system {
5149
return NSAppearance.current.getThemeName()
5250
} else {
5351
return Preferences.appearanceTheme
5452
}
5553
}
56-
private static var currentVisibility: AppearanceVisibilityPreference { Preferences.appearanceVisibility }
5754

5855
static func update() {
5956
updateSize()
@@ -78,10 +75,11 @@ class Appearance {
7875
} else {
7976
lightTheme()
8077
}
81-
// for Liquid Glass, we don't want a shadow around the panel
82-
if #available(macOS 26.0, *), currentStyle == .appIcons && LiquidGlassEffectView.canUsePrivateLiquidGlassLook() {
83-
enablePanelShadow = false
84-
}
78+
highlightBorderWidth = currentStyle == .titles ? 2 : 3
79+
// // for Liquid Glass, we don't want a shadow around the panel
80+
// if #available(macOS 26.0, *), currentStyle == .appIcons && LiquidGlassEffectView.canUsePrivateLiquidGlassLook() {
81+
// enablePanelShadow = false
82+
// }
8583
}
8684

8785
private static func thumbnailsSize(_ isHorizontalScreen: Bool) {
@@ -90,7 +88,6 @@ class Appearance {
9088
windowCornerRadius = 23
9189
cellCornerRadius = 10
9290
edgeInsetsSize = 12
93-
maxWidthOnScreen = 0.8
9491
if #available(macOS 26.0, *) {
9592
windowPadding = 28
9693
windowCornerRadius = 43
@@ -99,23 +96,19 @@ class Appearance {
9996
switch currentSize {
10097
case .small:
10198
rowsCount = isHorizontalScreen ? 5 : 8
102-
iconSize = 20
103-
fontHeight = 12
99+
iconSize = 16
100+
fontHeight = 13
104101
case .medium:
105102
rowsCount = isHorizontalScreen ? 4 : 7
106-
iconSize = 30
107-
fontHeight = 13
103+
iconSize = 26
104+
fontHeight = 14
108105
case .large:
109106
rowsCount = isHorizontalScreen ? 3 : 6
110-
iconSize = 32
107+
iconSize = 28
111108
fontHeight = 16
112109
}
113110
let thumbnailsPanelRatio = (NSScreen.preferred.frame.width * maxWidthOnScreen) / (NSScreen.preferred.frame.height * maxHeightOnScreen)
114111
(windowMinWidthInRow, windowMaxWidthInRow) = AppearanceTestable.goodValuesForThumbnailsWidthMinMax(thumbnailsPanelRatio, rowsCount)
115-
if currentVisibility == .highest {
116-
edgeInsetsSize = 10
117-
cellCornerRadius = 12
118-
}
119112
}
120113

121114
private static func appIconsSize() {
@@ -127,32 +120,31 @@ class Appearance {
127120
if #available(macOS 26.0, *) {
128121
edgeInsetsSize = 6
129122
}
130-
maxWidthOnScreen = 0.8
131123
windowMinWidthInRow = 0.04
132124
windowMaxWidthInRow = 0.3
133125
rowsCount = 1
134126
switch currentSize {
135127
case .small:
136-
iconSize = 88
128+
iconSize = 70
137129
fontHeight = 13
138130
if #available(macOS 26.0, *) {
139131
windowCornerRadius = 50
140-
cellCornerRadius = 28
132+
cellCornerRadius = 24
141133
}
142134
case .medium:
143-
iconSize = 128
144-
fontHeight = 15
135+
iconSize = 110
136+
fontHeight = 14
145137
if #available(macOS 26.0, *) {
146138
windowCornerRadius = 55
147-
cellCornerRadius = 38
139+
cellCornerRadius = 35
148140
}
149141
case .large:
150142
windowPadding = 28
151-
iconSize = 168
152-
fontHeight = 17
143+
iconSize = 150
144+
fontHeight = 16
153145
if #available(macOS 26.0, *) {
154146
windowCornerRadius = 75
155-
cellCornerRadius = 48
147+
cellCornerRadius = 45
156148
}
157149
}
158150
}
@@ -169,102 +161,26 @@ class Appearance {
169161
rowsCount = 1
170162
switch currentSize {
171163
case .small:
172-
iconSize = 20
164+
iconSize = 18
173165
fontHeight = 13
174166
case .medium:
175-
iconSize = 26
167+
iconSize = 24
176168
fontHeight = 14
177169
case .large:
178-
iconSize = 32
170+
iconSize = 22
179171
fontHeight = 16
180172
}
181173
}
182174

183175
private static func lightTheme() {
184176
fontColor = .black.withAlphaComponent(0.8)
185-
indicatedIconShadowColor = nil
186-
titleShadowColor = nil
187-
highlightMaterial = .mediumLight
188-
imageShadowColor = .lightGray.withAlphaComponent(0.4)
189-
switch currentVisibility {
190-
case .normal:
191-
material = .light
192-
highlightFocusedBackgroundColor = .lightGray.withAlphaComponent(0.7)
193-
highlightHoveredBackgroundColor = .lightGray.withAlphaComponent(0.5)
194-
enablePanelShadow = false
195-
highlightFocusedAlphaValue = 1.0
196-
highlightHoveredAlphaValue = 0.8
197-
highlightFocusedBorderColor = NSColor.clear
198-
highlightHoveredBorderColor = NSColor.clear
199-
highlightBorderShadowColor = NSColor.clear
200-
highlightBorderWidth = 0
201-
case .high:
202-
material = .mediumLight
203-
highlightFocusedBackgroundColor = .lightGray.withAlphaComponent(0.7)
204-
highlightHoveredBackgroundColor = .lightGray.withAlphaComponent(0.5)
205-
enablePanelShadow = true
206-
highlightFocusedAlphaValue = 1.0
207-
highlightHoveredAlphaValue = 0.8
208-
highlightFocusedBorderColor = .lightGray.withAlphaComponent(0.9)
209-
highlightHoveredBorderColor = .lightGray.withAlphaComponent(0.8)
210-
highlightBorderShadowColor = .black.withAlphaComponent(0.5)
211-
highlightBorderWidth = 1
212-
case .highest:
213-
material = .mediumLight
214-
highlightFocusedBackgroundColor = .lightGray.withAlphaComponent(0.4)
215-
highlightHoveredBackgroundColor = .lightGray.withAlphaComponent(0.3)
216-
enablePanelShadow = true
217-
highlightFocusedAlphaValue = 0.4
218-
highlightHoveredAlphaValue = 0.2
219-
highlightFocusedBorderColor = NSColor.systemAccentColor
220-
highlightHoveredBorderColor = NSColor.systemAccentColor.withAlphaComponent(0.8)
221-
highlightBorderShadowColor = .black.withAlphaComponent(0.5)
222-
highlightBorderWidth = currentStyle == .titles ? 2 : 4
223-
}
177+
imagesShadowColor = .gray.withAlphaComponent(0.8)
178+
material = .mediumLight
224179
}
225180

226181
private static func darkTheme() {
227-
fontColor = .white.withAlphaComponent(0.9)
228-
indicatedIconShadowColor = .darkGray
229-
titleShadowColor = .darkGray
230-
highlightMaterial = .ultraDark
231-
switch currentVisibility {
232-
case .normal:
233-
material = .dark
234-
imageShadowColor = .gray.withAlphaComponent(0.8)
235-
highlightFocusedBackgroundColor = .black.withAlphaComponent(0.6)
236-
highlightHoveredBackgroundColor = .black.withAlphaComponent(0.5)
237-
enablePanelShadow = false
238-
highlightFocusedAlphaValue = 1.0
239-
highlightHoveredAlphaValue = 0.8
240-
highlightFocusedBorderColor = NSColor.clear
241-
highlightHoveredBorderColor = NSColor.clear
242-
highlightBorderShadowColor = NSColor.clear
243-
highlightBorderWidth = 0
244-
case .high:
245-
material = .ultraDark
246-
imageShadowColor = .gray.withAlphaComponent(0.4)
247-
highlightFocusedBackgroundColor = .gray.withAlphaComponent(0.6)
248-
highlightHoveredBackgroundColor = .gray.withAlphaComponent(0.4)
249-
enablePanelShadow = true
250-
highlightFocusedAlphaValue = 1.0
251-
highlightHoveredAlphaValue = 0.8
252-
highlightFocusedBorderColor = .gray.withAlphaComponent(0.8)
253-
highlightHoveredBorderColor = .gray.withAlphaComponent(0.7)
254-
highlightBorderShadowColor = .white.withAlphaComponent(0.5)
255-
highlightBorderWidth = 1
256-
case .highest:
257-
material = .ultraDark
258-
imageShadowColor = .gray.withAlphaComponent(0.4)
259-
highlightFocusedBackgroundColor = .black.withAlphaComponent(0.4)
260-
highlightHoveredBackgroundColor = .black.withAlphaComponent(0.2)
261-
enablePanelShadow = true
262-
highlightFocusedAlphaValue = 0.4
263-
highlightHoveredAlphaValue = 0.2
264-
highlightFocusedBorderColor = NSColor.systemAccentColor
265-
highlightHoveredBorderColor = NSColor.systemAccentColor.withAlphaComponent(0.8)
266-
highlightBorderShadowColor = .white.withAlphaComponent(0.5)
267-
highlightBorderWidth = currentStyle == .titles ? 2 : 4
268-
}
182+
fontColor = .white.withAlphaComponent(0.85)
183+
imagesShadowColor = .gray.withAlphaComponent(0.8)
184+
material = .dark
269185
}
270186
}

src/logic/Application.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,13 @@ class Application: NSObject {
3333
static func appIconWithoutPadding(_ icon: NSImage?) -> CGImage? {
3434
guard let icon else { return nil }
3535
// we can render the icon quite big (e.g. windowless app icon), so we store it high-res
36-
let iconSize = CGFloat(1024)
36+
let iconWidth = CGFloat(1024)
3737
// NSRunningApplication.icon returns icons with padding; we remove it manually
3838
let paddingToRemove = CGFloat(84)
39-
let croppedSize = iconSize - paddingToRemove * 2
39+
let croppedSize = iconWidth - paddingToRemove * 2
4040
return icon
41-
.cgImage(maxSize: NSSize(width: iconSize, height: iconSize))
42-
.cropping(to: CGRect(x: paddingToRemove, y: paddingToRemove, width: croppedSize, height: croppedSize).integral)!
41+
.appIconFixedSize(NSSize(width: iconWidth, height: iconWidth))?
42+
.cropping(to: CGRect(x: paddingToRemove, y: paddingToRemove, width: croppedSize, height: croppedSize).integral)
4343
}
4444

4545
init(_ runningApplication: NSRunningApplication) {

src/logic/MacroPreferences.swift

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -484,28 +484,6 @@ enum AppearanceThemePreference: CaseIterable, SfSymbolMacroPreference {
484484
}
485485
}
486486

487-
enum AppearanceVisibilityPreference: CaseIterable, SfSymbolMacroPreference {
488-
case normal
489-
case high
490-
case highest
491-
492-
var localizedString: LocalizedString {
493-
switch self {
494-
case .normal: return NSLocalizedString("Normal", comment: "")
495-
case .high: return NSLocalizedString("High", comment: "")
496-
case .highest: return NSLocalizedString("Highest", comment: "")
497-
}
498-
}
499-
500-
var symbolName: String {
501-
switch self {
502-
case .normal: return "eye"
503-
case .high: return "eyeglasses"
504-
case .highest: return "binoculars.fill"
505-
}
506-
}
507-
}
508-
509487
enum UpdatePolicyPreference: CaseIterable, MacroPreference {
510488
case manual
511489
case autoCheck

src/logic/Preferences.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ class Preferences {
5050
"appearanceStyle": AppearanceStylePreference.thumbnails.indexAsString,
5151
"appearanceSize": AppearanceSizePreference.medium.indexAsString,
5252
"appearanceTheme": AppearanceThemePreference.system.indexAsString,
53-
"appearanceVisibility": AppearanceVisibilityPreference.normal.indexAsString,
5453
"theme": ThemePreference.macOs.indexAsString,
5554
"showOnScreen": ShowOnScreenPreference.active.indexAsString,
5655
"titleTruncation": TitleTruncationPreference.end.indexAsString,
@@ -129,7 +128,6 @@ class Preferences {
129128
static var appearanceStyle: AppearanceStylePreference { CachedUserDefaults.macroPref("appearanceStyle", AppearanceStylePreference.allCases) }
130129
static var appearanceSize: AppearanceSizePreference { CachedUserDefaults.macroPref("appearanceSize", AppearanceSizePreference.allCases) }
131130
static var appearanceTheme: AppearanceThemePreference { CachedUserDefaults.macroPref("appearanceTheme", AppearanceThemePreference.allCases) }
132-
static var appearanceVisibility: AppearanceVisibilityPreference { CachedUserDefaults.macroPref("appearanceVisibility", AppearanceVisibilityPreference.allCases) }
133131
// periphery:ignore
134132
static var theme: ThemePreference { ThemePreference.macOs/*CachedUserDefaults.macroPref("theme", ThemePreference.allCases)*/ }
135133
static var showOnScreen: ShowOnScreenPreference { CachedUserDefaults.macroPref("showOnScreen", ShowOnScreenPreference.allCases) }

0 commit comments

Comments
 (0)