カスタムクラス
import Foundation
fileprivate let kInterfaceStyle: String = "AppleInterfaceStyle"
protocol ThemeManagerDelegate: AnyObject {
func changedTheme(_ isDark: Bool, _ isDarkMenu: Bool)
}
final public class ThemeManager {
private let dnc = DistributedNotificationCenter.default()
weak var delegate: ThemeManagerDelegate?
init() {
// テーマ切り替え時のNotification
dnc.addObserver(self, selector: #selector(changedTheme), name: NSNotification.Name.themeChangedNotification, object: nil)
}
deinit {
dnc.removeObserver(self)
}
// テーマが切り替わるタイミングでの切り替わり後の全体のテーマ
@objc func changedTheme() {
let isDark: Bool = ThemeManager.isDark()
let isDarkMenu: Bool = ThemeManager.isDarkMenu()
delegate?.changedTheme(isDark, isDarkMenu)
}
// 訪ねたタイミングでの全体のテーマ
// 全体に対するテーマの概念が導入されたのはMojaveから
static func isDark() -> Bool {
if #available(OSX 10.14, *) {
if let style = UserDefaults.standard.string(forKey: kInterfaceStyle) {
return style.lowercased().contains("dark")
}
}
return false
}
// 訪ねたタイミングでのメニューバーのテーマ
// 古くからメニューバーにはダークモードの概念があった
static func isDarkMenu() -> Bool {
if let style = UserDefaults.standard.string(forKey: kInterfaceStyle) {
return style.lowercased().contains("dark")
}
return false
}
}
使用場面AppDelegate
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
private let theme = ThemeManager()
func applicationDidFinishLaunching(_ aNotification: Notification) {
theme.delegate = self
}
// 能動的なテーマ取得
func checkDarkMode() {
let isDark = ThemeManager.isDark()
let isDarkMenu = ThemeManager.isDarkMenu()
Swift.print(isDark, isDarkMenu)
}
}
extension AppDelegate: ThemeManagerDelegate {
// 受動的なテーマ取得
func changedTheme(_ isDark: Bool, _ isDarkMenu: Bool) {
Swift.print(isDark, isDarkMenu)
}
}
備考
Catalinaではライトモードでもダークモードでもないオートモードが追加されており,こちらのレポジトリによるとオートの時は取得したモードを反転させないといけないようだが,Catalina beta 9で確認したところ,反転させなくてよさそうだったため,仕様が揺れている可能性がある.