How to check dark mode in AppKit for macOS apps

Issue #693

AppKit app has its theme information stored in UserDefaults key AppleInterfaceStyle, if is dark, it contains String Dark.

Another way is to detect appearance via NSView

1
2
3
4
5
6
7
8
9
struct R {
static let dark = DarkTheme()
static let light = LightTheme()

static var theme: Theme {
let isDark = UserDefaults.standard.string(forKey: "AppleInterfaceStyle") == "Dark"
return isDark ? dark : light
}
}

Another way is to rely on appearance on NSView. You can quickly check via NSApp.keyWindow?.effectiveAppearance but notice that keyWindow can be nil when the app is not active since no window is focused for keyboard events. You should use NSApp.windows.first

1
let isDark = NSApp.windows.first?.effectiveAppearance.bestMatch(from: [.darkAqua, .vibrantDark]) == .darkAqua

Then build a simple Theme system

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import SwiftUI
import EasySwiftUI

protocol Theme {
var primaryColor: Color { get }
var textColor: Color { get }
var text2Color: Color { get }
var backgroundColor: Color { get }
var background2Color: Color { get }
}

extension Theme {
var primaryColor: Color { Color(hex: 0x1) }
}

struct DarkTheme: Theme {
...
}

struct LightTheme: Theme {
....
}

For SwiftUI, you can colorScheme environment, then use modifier .id(colorScheme) to force SwiftUI to update when color scheme changes

1
2
3
4
5
6
7
8
9
struct MainView: View {
@Environment(\.colorScheme)
var colorScheme

var body: some View {
VStack {}
.id(colorScheme)
}
}

Comments