Skip to content

Commit

Permalink
Disable on pre-defined battery level (Issue #24)
Browse files Browse the repository at this point in the history
  • Loading branch information
newmarcel committed Dec 28, 2015
1 parent 7a6df13 commit 049f678
Show file tree
Hide file tree
Showing 10 changed files with 434 additions and 34 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
- You can now set the default activation duration for the menu bar icon in preferences
- Removed the advanced preference for `info.marcel-dierkes.KeepingYouAwake.PreventSleepOnACPower`
- Added an advanced preference to allow display sleep while still preventing system sleep ([Issue #25](https://github.com/newmarcel/KeepingYouAwake/issues/25))
-
- Ability to set a battery level on MacBooks where the app will deactivate itself ([Issue #24](https://github.com/newmarcel/KeepingYouAwake/issues/24))
- *Thank you [timbru31](https://github.com/timbru31) for the suggestion!*

### v1.3.1 ###

Expand Down
14 changes: 14 additions & 0 deletions KeepingYouAwake.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
DA51E7DE1C2562A2008AA96C /* KYAActivationDuration.m in Sources */ = {isa = PBXBuildFile; fileRef = DA51E7DD1C2562A2008AA96C /* KYAActivationDuration.m */; };
DA5665A919FADED200B923FB /* NSApplication+LoginItem.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5665A819FADED200B923FB /* NSApplication+LoginItem.m */; };
DA5A50941ACC5C5400A444C8 /* KYAEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5A50931ACC5C5400A444C8 /* KYAEvent.m */; };
DA5B5A231C28612100EE45C6 /* KYABatteryStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5B5A221C28612100EE45C6 /* KYABatteryStatus.m */; };
DA637B3F19F14693004C8838 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DA637B3E19F14693004C8838 /* main.m */; };
DA637B4219F14693004C8838 /* KYAAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DA637B4119F14693004C8838 /* KYAAppDelegate.m */; };
DA637B4419F14693004C8838 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DA637B4319F14693004C8838 /* Images.xcassets */; };
Expand Down Expand Up @@ -55,6 +56,8 @@
DA5665A819FADED200B923FB /* NSApplication+LoginItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSApplication+LoginItem.m"; sourceTree = "<group>"; };
DA5A50921ACC5C5400A444C8 /* KYAEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KYAEvent.h; sourceTree = "<group>"; };
DA5A50931ACC5C5400A444C8 /* KYAEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KYAEvent.m; sourceTree = "<group>"; };
DA5B5A211C28612100EE45C6 /* KYABatteryStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KYABatteryStatus.h; sourceTree = "<group>"; };
DA5B5A221C28612100EE45C6 /* KYABatteryStatus.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KYABatteryStatus.m; sourceTree = "<group>"; };
DA637B3919F14693004C8838 /* KeepingYouAwake.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = KeepingYouAwake.app; sourceTree = BUILT_PRODUCTS_DIR; };
DA637B3D19F14693004C8838 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
DA637B3E19F14693004C8838 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -161,6 +164,15 @@
name = About;
sourceTree = "<group>";
};
DA5B5A241C28612800EE45C6 /* Battery Status */ = {
isa = PBXGroup;
children = (
DA5B5A211C28612100EE45C6 /* KYABatteryStatus.h */,
DA5B5A221C28612100EE45C6 /* KYABatteryStatus.m */,
);
name = "Battery Status";
sourceTree = "<group>";
};
DA637B3019F14693004C8838 = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -192,6 +204,7 @@
DAB268711A0D6BC600B58AD6 /* KYASleepWakeTimer.m */,
DA82B1111C2422F600FA46E0 /* Preferences */,
DA2691CF1B8230AB00B15779 /* MenuBar Icon */,
DA5B5A241C28612800EE45C6 /* Battery Status */,
DA4919C51ACFFF8D00D44F6A /* Event Handler */,
DA4919C61ACFFF9600D44F6A /* Extensions */,
);
Expand Down Expand Up @@ -324,6 +337,7 @@
buildActionMask = 2147483647;
files = (
DA5665A919FADED200B923FB /* NSApplication+LoginItem.m in Sources */,
DA5B5A231C28612100EE45C6 /* KYABatteryStatus.m in Sources */,
DA46C1EE1BDCDFB00050357C /* NSUserDefaults+Keys.m in Sources */,
DA637B4219F14693004C8838 /* KYAAppDelegate.m in Sources */,
DA5A50941ACC5C5400A444C8 /* KYAEvent.m in Sources */,
Expand Down
9 changes: 9 additions & 0 deletions KeepingYouAwake/KYAAdvancedPreferencesViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@
#import <Cocoa/Cocoa.h>

@interface KYAAdvancedPreferencesViewController : NSViewController

/**
* Determines if the current Mac has a built-in battery.
*/
@property (nonatomic, readonly, getter=isBatteryStatusAvailable) BOOL batteryStatusAvailable;

/**
* A table view reference.
*/
@property (weak, nonatomic, nullable) IBOutlet NSTableView *tableView;

/**
Expand Down
20 changes: 16 additions & 4 deletions KeepingYouAwake/KYAAdvancedPreferencesViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@

#import "KYAAdvancedPreferencesViewController.h"
#import "KYAPreference.h"
#import "KYABatteryStatus.h"
#import "NSUserDefaults+Keys.h"

@interface KYAAdvancedPreferencesViewController () <NSTableViewDataSource, NSTableViewDelegate>
@property (nonatomic, nonnull) NSArray<KYAPreference *> *preferences;
@property (nonatomic, readwrite) BOOL batteryStatusAvailable;
@property (weak, nonatomic) IBOutlet NSUserDefaultsController *defaultsController;
@end

@implementation KYAAdvancedPreferencesViewController
Expand All @@ -20,6 +23,9 @@ - (void)viewDidLoad
{
[super viewDidLoad];

// Check the battery status
self.batteryStatusAvailable = [[KYABatteryStatus new] isBatteryStatusAvailable];

[self configureAdvancedPreferences];
}

Expand All @@ -36,10 +42,6 @@ - (void)configureAdvancedPreferences
{
NSMutableArray *preferences = [NSMutableArray new];

[preferences addObject:[[KYAPreference alloc] initWithTitle:NSLocalizedString(@"Disable menu bar icon highlight color", nil)
defaultsKey:KYAUserDefaultsKeyMenuBarIconHighlightDisabled
]];

[preferences addObject:[[KYAPreference alloc] initWithTitle:NSLocalizedString(@"Enable experimental Notification Center integration", nil)
defaultsKey:KYAUserDefaultsKeyNotificationsEnabled
]];
Expand All @@ -48,6 +50,10 @@ - (void)configureAdvancedPreferences
defaultsKey:KYAUserDefaultsKeyAllowDisplaySleep
]];

[preferences addObject:[[KYAPreference alloc] initWithTitle:NSLocalizedString(@"Disable menu bar icon highlight color", nil)
defaultsKey:KYAUserDefaultsKeyMenuBarIconHighlightDisabled
]];

self.preferences = [preferences copy];
}

Expand All @@ -61,6 +67,12 @@ - (IBAction)resetAdvancedPreferences:(id)sender
}
[[NSUserDefaults standardUserDefaults] synchronize];
[self.tableView reloadData];

// Disable battery status integration
NSString *keyPath = [NSString stringWithFormat:@"values.%@", KYAUserDefaultsKeyBatteryCapacityThresholdEnabled];
[self.defaultsController setValue:@NO forKeyPath:keyPath];
keyPath = [NSString stringWithFormat:@"values.%@", KYAUserDefaultsKeyBatteryCapacityThreshold];
[self.defaultsController setValue:@10.0f forKeyPath:keyPath];
}

#pragma mark - Table View Delegate & Data Source
Expand Down
101 changes: 85 additions & 16 deletions KeepingYouAwake/KYAAppController.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@
#import "KYASleepWakeTimer.h"
#import "KYAEventHandler.h"
#import "KYAMenuBarIcon.h"
#import "KYABatteryStatus.h"
#import "NSUserDefaults+Keys.h"

@interface KYAAppController () <NSUserNotificationCenterDelegate>
@property (strong, nonatomic, readwrite) KYASleepWakeTimer *sleepWakeTimer;
@property (nonatomic) KYABatteryStatus *batteryStatus;
@property (nonatomic, getter=isBatteryOverrideEnabled) BOOL batteryOverrideEnabled;
@property (nonatomic, readwrite) KYASleepWakeTimer *sleepWakeTimer;

// Status Item
@property (strong, nonatomic) NSStatusItem *statusItem;
Expand Down Expand Up @@ -43,20 +46,31 @@ - (instancetype)init
[self activateTimer];
}

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillFinishLaunching:)
name:NSApplicationWillFinishLaunchingNotification
object:nil
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self
selector:@selector(applicationWillFinishLaunching:)
name:NSApplicationWillFinishLaunchingNotification
object:nil
];

if([self.batteryStatus isBatteryStatusAvailable])
{
[notificationCenter addObserver:self
selector:@selector(userDefaultsDidChange:)
name:NSUserDefaultsDidChangeNotification
object:nil];
}

[self configureEventHandler];
}
return self;
}

- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationDidFinishLaunchingNotification object:nil];
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter removeObserver:self name:NSApplicationDidFinishLaunchingNotification object:nil];
[notificationCenter removeObserver:self name:NSUserDefaultsDidChangeNotification object:nil];
}

- (void)awakeFromNib
Expand Down Expand Up @@ -181,6 +195,9 @@ - (void)activateTimerWithTimeInterval:(NSTimeInterval)timeInterval
return;
}

// Check if the activation overrides the battery threshold
[self checkAndEnableBatteryOverride];

[self.sleepWakeTimer scheduleWithTimeInterval:timeInterval completion:^(BOOL cancelled) {
// Post notifications
if([[NSUserDefaults standardUserDefaults] kya_areNotificationsEnabled])
Expand Down Expand Up @@ -216,17 +233,19 @@ - (void)activateTimerWithTimeInterval:(NSTimeInterval)timeInterval

- (void)terminateTimer
{
[self.sleepWakeTimer invalidate];
[self disableBatteryOverride];

if([self.sleepWakeTimer isScheduled])
{
[self.sleepWakeTimer invalidate];
}
}

#pragma mark - Menu Delegate

- (IBAction)selectTimeInterval:(NSMenuItem *)sender
{
if([self.sleepWakeTimer isScheduled])
{
[self.sleepWakeTimer invalidate];
}
[self terminateTimer];

if (sender.alternate)
{
Expand Down Expand Up @@ -307,6 +326,60 @@ - (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentN
return YES;
}

#pragma mark - Battery Status

- (KYABatteryStatus *)batteryStatus
{
if(_batteryStatus == nil)
{
_batteryStatus = [KYABatteryStatus new];

__weak typeof(self) weakSelf = self;
_batteryStatus.capacityChangeHandler = ^(CGFloat capacity) {
[weakSelf batteryCapacityDidChange:capacity];
};
}
return _batteryStatus;
}

- (void)checkAndEnableBatteryOverride
{
CGFloat currentCapacity = self.batteryStatus.currentCapacity;
CGFloat threshold = [NSUserDefaults standardUserDefaults].kya_batteryCapacityThreshold;

self.batteryOverrideEnabled = (currentCapacity <= threshold);
}

- (void)disableBatteryOverride
{
self.batteryOverrideEnabled = NO;
}

- (void)batteryCapacityDidChange:(CGFloat)capacity
{
CGFloat threshold = [NSUserDefaults standardUserDefaults].kya_batteryCapacityThreshold;
if([self.sleepWakeTimer isScheduled] && (capacity <= threshold) && ![self isBatteryOverrideEnabled])
{
[self terminateTimer];
}
}

#pragma mark - User Defaults

- (void)userDefaultsDidChange:(NSNotification *)notification
{
NSUserDefaults *defaults = (NSUserDefaults *)notification.object;

if([self.batteryStatus isBatteryStatusAvailable] && [defaults kya_isBatteryCapacityThresholdEnabled])
{
[self.batteryStatus registerForCapacityChangesIfNeeded];
}
else
{
[self.batteryStatus unregisterFromCapacityChanges];
}
}

#pragma mark - Apple Event Manager

- (void)applicationWillFinishLaunching:(NSNotification *)notification
Expand All @@ -318,7 +391,6 @@ - (void)applicationWillFinishLaunching:(NSNotification *)notification
];
}


- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)reply
{
NSString *value = [event paramDescriptorForKeyword:keyDirectObject].stringValue;
Expand All @@ -335,10 +407,7 @@ - (void)configureEventHandler
NSString *minutes = parameters[@"minutes"];
NSString *hours = parameters[@"hours"];

if([self.sleepWakeTimer isScheduled])
{
[self.sleepWakeTimer invalidate];
}
[self terminateTimer];

// Activate indefinitely if there are no parameters
if(parameters.count == 0)
Expand Down
48 changes: 48 additions & 0 deletions KeepingYouAwake/KYABatteryStatus.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// KYABatteryStatus.h
// KeepingYouAwake
//
// Created by Marcel Dierkes on 21.12.15.
// Copyright © 2015 Marcel Dierkes. All rights reserved.
//

#import <Foundation/Foundation.h>

const CGFloat KYABatteryStatusUnavailable;

typedef void(^KYABatteryStatusChangeBlock)(CGFloat capacity);

/**
* An object that represents the current battery capacity.
*/
@interface KYABatteryStatus : NSObject

/**
* Returns YES if the current device actually has a built-in battery.
*/
@property (nonatomic, readonly, getter=isBatteryStatusAvailable) BOOL batteryStatusAvailable;

/**
* Returns the current battery charging level of the internal battery, or KYABatteryStatusUnavailable.
*/
@property (nonatomic, readonly) CGFloat currentCapacity;

/**
* An optional block that will be called when the power source changes and registerForCapacityChanges was called.
*/
@property (copy, nonatomic, nullable) KYABatteryStatusChangeBlock capacityChangeHandler;

/**
* Registers the current instance with the runloop to receive power source change notifications.
*
* The capacityChangeHandler block will be called when a power source change occurs.
*/
- (void)registerForCapacityChangesIfNeeded;

/**
* Unregisters the current instance from all capacity change notifications.
* This method will automatically be called on dealloc.
*/
- (void)unregisterFromCapacityChanges;

@end
Loading

0 comments on commit 049f678

Please sign in to comment.