Reputation: 1759
I'm creating an agent app for OS X in swift (only showing the app icon in the menu bar). I'm loading the icon for the app from the AppDelegate using:
statusItem.image = NSImage(named: "BlackIcon")
and it works fine.
However, if the user has chosen to use the dark menu bar from the System Preferences -> General, the user won't see the icon as it's black.
So I need to display a different 'WhiteIcon' to the user if they have the option selected.
How can I check whether the user has this option active from my app?
Upvotes: 3
Views: 814
Reputation: 2942
It appears that you are trying to invert menulet icon color for dark mode. By default OSX handles darkmode and inverts the image color, however you need to specifically add [image setTemplate:YES] to have this work for you if it already doesnt.
Objective-c:
self.statusItem = [[NSStatusBar systemStatusBar]
statusItemWithLength:NSSquareStatusItemLength];
NSImage *image = [NSImage imageNamed:@"statusItemIcon"];
[image setTemplate:YES];
[self.statusItem setImage:image];
swift: (Originally answered by Zhi-Wei Cai at link below)
var isDark = false
func isDarkMode() {
// Swift2
// isDark = NSAppearance.currentAppearance().name.hasPrefix("NSAppearanceNameVibrantDark")
// Swift3+
isDark = NSAppearance.current.name.rawValue.hasPrefix("NSAppearanceNameVibrantDark")
}
override func drawRect(dirtyRect: NSRect) {
super.drawRect(dirtyRect)
isDarkMode()
// Now use "isDark" to determine the drawing colour.
if isDark {
// ...
} else {
// ...
}
}
This answer explains it in the detail: NSStatusItem change image for dark tint
Upvotes: 1
Reputation: 653
With Swift 3.0, you can use the UserDefaults to access the macOS appearance, or "AppleInterfaceStyle", using the following code:
let mode = UserDefaults.standard.string(forKey: "AppleInterfaceStyle")
If the user has enabled dark mode, the defaults will return a string "Dark". If they have the "light mode" enabled it will return nil. So you will need to wrap that in the following code:
if UserDefaults.standard.string(forKey: "AppleInterfaceStyle") == "Dark" {
statusItem.image = NSImage(named: "WhiteIcon")
} else {
statusItem.image = NSImage(named: "BlackIcon")
}
I'm sure there might be a cleaner way, maybe with a guard but that will get you where you need to be in Swift 3.0
Edit:
The above code will determine the users current "mode". However, using a simple check for the users preference will not result in the correct behavior (e.g. it will only fire when the application starts).
The correct method of performing this is to set the menu icon as a black icon. Then, browse to the asset in the Asset Catalog, and select the menu icon. With the menu selected, browse to the Attributes Inspector and make sure the image is checked with a “Mac” device. Then choose “Render As” set to “Template Image”.
This only requires you to have one icon, in black, and macOS will handle the conversion of the images from dark to light modes.
Upvotes: 4