Reset users default app brightness in applicationDidEnterBackground with swift - xcode

I've been trying to reset the user's default device brightness in the app delegate method: applicationDidEnterBackground by using this code:
UIScreen.mainScreen().brightness = screenBrightness!
The code gets called but the brightness is not reset. Anyone know how to get this working using Swift (not obj-c)

This code looks correct, but note that it will not work in the simulator, it will only take effect on a physical device.
Also, ensure that the value of screenBrightness is between 0 and 1.
You will likely not be able to change the screen brightness while in the background. From Apple's documentation:
Brightness changes made by an app remain in effect only while the app
is active. The system restores the user-supplied brightness setting at
appropriate times when your app is not in the foreground.

You need to change the brightness in the AppDelegate. For some reason it doesn't work properly when triggered in a view controller from a notification (willResignActiveNotification, didEnterBackgroundNotification, willTerminateNotification). Although, you can use AppDelegate methods for that:
func applicationWillResignActive(_ application: UIApplication) {
UIScreen.main.brightness = 0.5
}

Related

Updating for dark mode: NSColor ignores appearance changes?

In my web view, I'm using CSS variables to change various colors at runtime depending on whether macOS 10.14's dark mode is enabled. That much is working fine. The tricky part is updating the colors when the system appearance changes.
I'm detecting the change by observing the effectiveAppearance property on the window. That notification comes through as expected, but when I go to update the colors, NSColor still gives me the dark mode colors (or whichever mode the app started up in). For example, NSColor.textColor is is still white instead of black when I'm responding to a switch from dark mode to light. The same seems to happen with my own color assets.
Is there a different way or time that I should get these colors? Or could this be an OS bug?
Edit:
I also tried creating a subclass of WebView and updating my colors in drawRect() if the name of the web view's effective appearance changes. The first time, I get all light colors, even when the app starts up in dark mode. After that, when I switch from light mode to dark, I get the dark versions of system colors and light versions of asset catalog colors.
Outside the debugger, switching to dark mode works, but the initial load always gets light colors.
Changing the system appearance doesn't change the current appearance, which you can query and set and is independent from the system appearance. But the appearance actually depends on the "owning" view as within the same view hierarchy, several appearances may occur thanks to vibrancy and also manually setting the appearance property on a view.
Cocoa already updates the current appearance in a few situations, like in drawRect:, updateLayer, layout and updateConstraints. Everywhere else, you should do it like this:
NSAppearance * saved = [NSAppearance currentAppearance];
[NSAppearance setCurrentAppearance:someView.effectiveAppearance];
// Do your appearance-dependent work, like querying the CGColor from
// a dynamic NSColor or getting its RGB values.
[NSAppearance setCurrentAppearance:saved];
And a Swifty version of the solution proposed by DarkDust:
extension NSAppearance {
static func withAppAppearance<T>(_ closure: () throws -> T) rethrows -> T {
let previousAppearance = NSAppearance.current
NSAppearance.current = NSApp.effectiveAppearance
defer {
NSAppearance.current = previousAppearance
}
return try closure()
}
}
that you can use with
NSAppearance.withAppAppearance {
let bgColor = NSColor.windowBackgroundColor
// ...
}
Note that I'm taking appearance from NSApp but it could be from a NSWindow or NSView.
The currentAppearance property used in previous answers is now deprecated. The alternative as of macOS 11 Big Sur is to use the performAsCurrentDrawingAppearance: instance method.
As mentioned by #chrstphrchvz, NSAppearance.current is deprecated when using macOS 11 or newer. The new way to update anything with the latest appearance system settings works like this:
NSAppearance.currentDrawing().performAsCurrentDrawingAppearance {
// Update your window or control or whatever
}

Need help setting up an interface where rotation is fixed for most elements, but alert and sharing boxes auto-rotate with the device

I'm working with Xcode 7 and Swift 2. I am working on an interface with a camera preview layer and controls that display in a manner similar to the native iOS camera app. The controls all stay in place as you turn the device, but the icons "pivot" in place to orient properly for the device orientation. (I hope I explained that in a way that makes sense. If not, open the native camera app on your iPhone and turn the device around a few times to see what I'm talking about.)
I have the basic interface working already by fixing the overall interface orientation using:
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.LandscapeRight
}
Then I use transform to rotate each button for the device orientation.
The problem is: I need to be able to present alert messages (UIAlertController) and a sharing interface (UIActivityViewController) in this same interface. How do I get those items to rotate to the correct orientation while still keeping the rest of the interface static?
As I see it, there are two possible approaches here -- I just don't know how to make either one work:
Set the interface to auto rotate and support all orientations, but disable auto-rotation for the views that I need to keep locked in place.
Set the interface to only allow .landscapeLeft (which is currently how it's set up) and find a way to rotate the alert messages and sharing dialog box.
Got it working. I needed to access presentedViewController.view to rotate the alert and share views.
//used to periodically trigger a check of orientation
var updateTimer: NSTimer?
//Checks if the device has rotated and, if so, rotates the controls. Also prompts the user that portrait orientation is bad.
func checkOrientation(timer: NSTimer) {
//Array of the views that need to be rotated as the device rotates
var viewsToRotate = [oneView, anotherView]
//This adds the alert or sharing view to the list, if there is one
if let presentedVC = presentedViewController?.view {
viewsToRotate.append(presentedVC)
}
//Rotate all of the views identified above
for viewToRotate in viewsToRotate {
switch UIDevice.currentDevice().orientation {
case UIDeviceOrientation.Portrait:
viewToRotate.transform = CGAffineTransformMakeRotation(CGFloat(-M_PI_2))
case UIDeviceOrientation.PortraitUpsideDown:
viewToRotate.transform = CGAffineTransformMakeRotation(CGFloat(M_PI_2))
case UIDeviceOrientation.LandscapeRight:
viewToRotate.transform = CGAffineTransformMakeRotation(CGFloat(2 * M_PI_2))
default:
viewToRotate.transform = CGAffineTransformMakeRotation(CGFloat(0))
}
}
}

NSStatusItem with custom view, alpha value, and multiple displays

I have an app which has a NSStatusItem that uses a custom view. I apply an alpha value to the status item's view when a process in the app in inactive. This works fine, except on OS X 10.9 - 10.10 when multiple displays (monitors) are present. The system menu bar auto-applies an alpha value to itself when it is on an inactive display. On the inactive display, the custom view in my status item seems to completely disappear.
I am guessing that OS X auto-applying an alpha value to the menu bar on the inactive display is combining with the alpha value I am setting directly to the view and causing the view to have an overall alpha value of 0 or less.
Any ideas on how to handle this? Thanks in advance!
As far as I know, to display an inactive NSStatusItem you should use another image, that is the same as the one used when active, but with a grey color (and that image must have template = true).
I guess that applying an alphaValue to the item works just because that is the way that the system uses when a second monitor is attached.

Make application startup with size and position it was when it was closed

I'm currently creating a application that, when it reopens need to have the same size and screen position as just before it was closed.
I hope that it is just a checkmark in interface builder that i haven't noticed.
Thanks! :-)
You should implement Application Persistence.
Read more here.
When a user logs out, Lion offers them the option to restore all open apps to their current state when logging back in. To support this feature in your app you must determine for each window whether its state should be preserved using the -setRestorable: method. Cocoa will then take care of saving the state (size, position, etc.) of your windows and their associated window controllers, giving you the option to write out additional state information of custom objects associated with the windows.
To restore your application’s state when it is relaunched, every window must specify a so-called restoration class through the +restoreWindowWithIdentifier:state:completionHandler: class method (defined in the NSWindowRestoration protocol). The restoration class is then responsible for instantiating the window and its associated objects (such as the window controller). See the User Interface Preservation topic in the Mac OS X Application Programming Guide for a step by step guide.
Close to a checkbox. Set the window's frame auto-save name. That's a key naming a value in the app's preferences (which is managed by NSWindow) under which the window's frame is stored and retrieved.
Store size and position in NSUserDefaults.For example you store a cgpoint in Nsuserdefaults
as follows
CGPoint *point=CGPointMake(34,67);
NSUserDefaults* def=[NSUserDefaults standardUserDefaults];
NSString* mypointstr=NSStringFromCGPoint(point);
[def SetObject:mypointstr:forkey:#"mypoint"];
to get this next time the app starts
NSString* myprevstr=[def Objectforkey:#"mypoint"]
CGPoint* point=CGPointFromString(myprevstr);

Stop Device orientation

While running my app I get errors which indicate that rotation notifications are being sent and crashing the app. Is there a way I can stop all rotation events from being sent to see if I can stop the crashes. Also is there a good overview of how these events should be handled. Do I have to handle them separately in in controllers or in all views. For the moment I would be quite happy to lock in portrait.
I have tried calling [[UIDevice currentDevice] endGenerating Device OrientationNotifications];
but I am still getting device Orientation DidChange events unrecognized selector sent to instance
You can't stop rotation notifications, nor should you try to.
The notifications aren't causing your crash, you must have some bad code in there.
Paste your exact error from the console and the code for the view controller where it's happening. My guess is that you've written a rotation handler method that doesn't work, possibly without realising it.
You can lock in portrait by creating a view controller base class that has this method, then using it as the superclass for all your other view controllers:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return toInterfaceOrientation == UIInterfaceOrientationPortrait;
}

Resources