Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

App improvements #1

Closed
wants to merge 12 commits into from

2 participants

@mac-cain13

I made a number of improvements to your App to make it somewhat more useful for me. The main improvements/thing I added are:

  • Start on login functionality
  • Battery icon
  • Time remaining when charging the battery
  • Textual improvements (less special chars)
  • Some small code improvements

If you want you can merge my improvements into your branch. I think I will improve my version somewhat further in the next days, will send a new pull request by then.

mac-cain13 added some commits
@mac-cain13 mac-cain13 Removed special chars in statusbar and cleaned up the code a bit
- Removed special chars around the message in the menubar
- Call IOPSGetTimeRemainingEstimate() only once
- Added comments
- Using more properties to improve readability
d9e3790
@mac-cain13 mac-cain13 Added a simple readme for Github 6c15d58
@mac-cain13 mac-cain13 Fixed contibutors d57ff19
@mac-cain13 mac-cain13 Added start at login option cd82cdd
@mac-cain13 mac-cain13 Changed texts when full and when calculating
- Calculcating => Calculating…
- Unlimited => ∞
3662ebd
@mac-cain13 mac-cain13 Update Readme.md ac6e1e7
@mac-cain13 mac-cain13 Also display time until fully charged
also updated copyright notice in info plist
06a6121
@mac-cain13 mac-cain13 Using the Apple battery icon
We now show the Apple battery icon in the menubar
f948894
@mac-cain13 mac-cain13 Sign release builds with the Wrep Developer ID
also ignore XCode userdata/workspace
5335c49
@mac-cain13 mac-cain13 Fixed stupid mistake where the icon was not correctly zit c972361
@mac-cain13 mac-cain13 Install instructions update
also added links to contributors and how to contribute
878c63c
@mac-cain13 mac-cain13 Merge branch 'refs/heads/development' 5f8af5e
@codler
Owner

Thank you very much for improving and adding more feature!! I really appreciate it! This is my first mac app so any improvements and suggestions etc are welcome :)

I merged all your commits except one, the "CODE_SIGN_IDENTITY".
I also made some improvements and fixed a bug.

@codler codler closed this
@mac-cain13

Great that you accepted the pull request! I understand why you didn't accept the code sign commit, but you should sign the builds you publish with a Developer ID. If you don't code sign builds Gatekeeper will prevent users from installing it!

@codler
Owner

oh, is that why. To get Developer ID I must have Mac Developer Program membership and it cost $99/year which is expensive. As a student that is too much for me =( It would be okey with one time fee, but per year is...

@mac-cain13

I get that, my company has an Mac Developer Account and can sign builds, so maybe we can figure something out to get out signed builds. At least I can sign the builds I make and put online. :)

@codler
Owner

I decided to join the program :P and now I can sign.

@mac-cain13

Great to hear you've joined. :) Looking forward to a lot of signed builds!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Aug 4, 2012
  1. @mac-cain13

    Removed special chars in statusbar and cleaned up the code a bit

    mac-cain13 authored
    - Removed special chars around the message in the menubar
    - Call IOPSGetTimeRemainingEstimate() only once
    - Added comments
    - Using more properties to improve readability
  2. @mac-cain13
  3. @mac-cain13

    Fixed contibutors

    mac-cain13 authored
  4. @mac-cain13
  5. @mac-cain13

    Changed texts when full and when calculating

    mac-cain13 authored
    - Calculcating => Calculating…
    - Unlimited => ∞
  6. @mac-cain13

    Update Readme.md

    mac-cain13 authored
  7. @mac-cain13

    Also display time until fully charged

    mac-cain13 authored
    also updated copyright notice in info plist
  8. @mac-cain13

    Using the Apple battery icon

    mac-cain13 authored
    We now show the Apple battery icon in the menubar
  9. @mac-cain13

    Sign release builds with the Wrep Developer ID

    mac-cain13 authored
    also ignore XCode userdata/workspace
  10. @mac-cain13
  11. @mac-cain13

    Install instructions update

    mac-cain13 authored
    also added links to contributors and how to contribute
  12. @mac-cain13
This page is out of date. Refresh to see the latest.
View
2  .gitignore
@@ -0,0 +1,2 @@
+/Battery Time Remaining.xcodeproj/xcuserdata/
+/Battery Time Remaining.xcodeproj/project.xcworkspace/
View
15 Battery Time Remaining.xcodeproj/project.pbxproj
@@ -14,6 +14,7 @@
2841C7F415C91CC100F4F15F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2841C7F315C91CC100F4F15F /* AppDelegate.m */; };
2841C7F715C91CC200F4F15F /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2841C7F515C91CC200F4F15F /* MainMenu.xib */; };
2841C7FE15C91CEF00F4F15F /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2841C7FD15C91CEF00F4F15F /* IOKit.framework */; };
+ D58C7EF815CD7C6100C07E0C /* StartAtLoginHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = D58C7EF715CD7C6100C07E0C /* StartAtLoginHelper.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@@ -31,6 +32,8 @@
2841C7F315C91CC100F4F15F /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
2841C7F615C91CC200F4F15F /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = "<group>"; };
2841C7FD15C91CEF00F4F15F /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };
+ D58C7EF615CD7C6100C07E0C /* StartAtLoginHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StartAtLoginHelper.h; sourceTree = "<group>"; };
+ D58C7EF715CD7C6100C07E0C /* StartAtLoginHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StartAtLoginHelper.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -49,7 +52,6 @@
2841C7D115C91CC100F4F15F = {
isa = PBXGroup;
children = (
- 2841C7FD15C91CEF00F4F15F /* IOKit.framework */,
2841C7E615C91CC100F4F15F /* Battery Time Remaining */,
2841C7DF15C91CC100F4F15F /* Frameworks */,
2841C7DD15C91CC100F4F15F /* Products */,
@@ -67,6 +69,7 @@
2841C7DF15C91CC100F4F15F /* Frameworks */ = {
isa = PBXGroup;
children = (
+ 2841C7FD15C91CEF00F4F15F /* IOKit.framework */,
2841C7E015C91CC100F4F15F /* Cocoa.framework */,
2841C7E215C91CC100F4F15F /* Other Frameworks */,
);
@@ -88,6 +91,8 @@
children = (
2841C7F215C91CC100F4F15F /* AppDelegate.h */,
2841C7F315C91CC100F4F15F /* AppDelegate.m */,
+ D58C7EF615CD7C6100C07E0C /* StartAtLoginHelper.h */,
+ D58C7EF715CD7C6100C07E0C /* StartAtLoginHelper.m */,
2841C7F515C91CC200F4F15F /* MainMenu.xib */,
2841C7E715C91CC100F4F15F /* Supporting Files */,
);
@@ -172,6 +177,7 @@
files = (
2841C7ED15C91CC100F4F15F /* main.m in Sources */,
2841C7F415C91CC100F4F15F /* AppDelegate.m in Sources */,
+ D58C7EF815CD7C6100C07E0C /* StartAtLoginHelper.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -213,6 +219,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
@@ -241,6 +248,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "Developer ID Application: Wrep";
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_C_LANGUAGE_STANDARD = gnu99;
@@ -250,6 +258,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.8;
+ PROVISIONING_PROFILE = "";
SDKROOT = macosx;
};
name = Release;
@@ -257,6 +266,7 @@
2841C7FB15C91CC200F4F15F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ CODE_SIGN_IDENTITY = "";
COMBINE_HIDPI_IMAGES = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "Battery Time Remaining/Battery Time Remaining-Prefix.pch";
@@ -269,11 +279,13 @@
2841C7FC15C91CC200F4F15F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ CODE_SIGN_IDENTITY = "Developer ID Application: Wrep";
COMBINE_HIDPI_IMAGES = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "Battery Time Remaining/Battery Time Remaining-Prefix.pch";
INFOPLIST_FILE = "Battery Time Remaining/Battery Time Remaining-Info.plist";
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE = "";
WRAPPER_EXTENSION = app;
};
name = Release;
@@ -297,6 +309,7 @@
2841C7FC15C91CC200F4F15F /* Release */,
);
defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
View
4 Battery Time Remaining/AppDelegate.h
@@ -10,9 +10,11 @@
@interface AppDelegate : NSObject <NSApplicationDelegate>
-- (NSString*)GetTimeRemainingText;
+- (void)updateStatusItem;
+- (NSImage *)getBatteryIconNamed:(NSString *)iconName;
@property (assign) IBOutlet NSWindow *window;
@property (strong) NSStatusItem *statusItem;
+@property (strong) NSMenuItem *startupToggle;
@end
View
139 Battery Time Remaining/AppDelegate.m
@@ -7,49 +7,138 @@
//
#import "AppDelegate.h"
+#import "StartAtLoginHelper.h"
#import <IOKit/ps/IOPowerSources.h>
+#import <IOKit/ps/IOPSKeys.h>
-static void PowerSourceChanged(void * context) {
-
- AppDelegate * self = (__bridge AppDelegate *)context;
- [self.statusItem setTitle:[self GetTimeRemainingText]];
+// IOPS notification callback on power source change
+static void PowerSourceChanged(void * context)
+{
+ // Update the time remaining text
+ AppDelegate *self = (__bridge AppDelegate *)context;
+ [self updateStatusItem];
}
@implementation AppDelegate
-@synthesize statusItem;
+@synthesize statusItem, startupToggle;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
- NSMenu *stackMenu = [[NSMenu alloc] initWithTitle:@"Status Menu"];
- [stackMenu addItemWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@""];
+ // Create the startup at login toggle
+ self.startupToggle = [[NSMenuItem alloc] initWithTitle:@"Start at login" action:@selector(toggleStartAtLogin:) keyEquivalent:@""];
+ self.startupToggle.target = self;
+ self.startupToggle.state = ([StartAtLoginHelper isInLoginItems]) ? NSOnState : NSOffState;
- statusItem = [[NSStatusBar systemStatusBar]
- statusItemWithLength:NSVariableStatusItemLength];
- [statusItem setHighlightMode:YES];
- [statusItem setMenu:stackMenu];
+ // Build the status menu
+ NSMenu *statusMenu = [[NSMenu alloc] initWithTitle:@"Status Menu"];
+ [statusMenu addItem:self.startupToggle];
+ [statusMenu addItemWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@""];
- NSString *title = [self GetTimeRemainingText];
+ // Create the status item and set initial text
+ statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
+ statusItem.highlightMode = YES;
+ statusItem.menu = statusMenu;
+ [self updateStatusItem];
- [statusItem setTitle:title];
-
- // Update Power Source
+ // Capture Power Source updates and make sure our callback is called
CFRunLoopSourceRef loop = IOPSNotificationCreateRunLoopSource(PowerSourceChanged, (__bridge void *)self);
CFRunLoopAddSource(CFRunLoopGetCurrent(), loop, kCFRunLoopDefaultMode);
CFRelease(loop);
}
-- (NSString*)GetTimeRemainingText
+- (void)updateStatusItem
+{
+ // Get the estimated time remaining
+ CFTimeInterval timeRemaining = IOPSGetTimeRemainingEstimate();
+
+ // We're connected to an unlimited power source (AC adapter probably)
+ if (kIOPSTimeRemainingUnlimited == timeRemaining)
+ {
+ // Get list of power sources
+ CFTypeRef psBlob = IOPSCopyPowerSourcesInfo();
+ CFArrayRef psList = IOPSCopyPowerSourcesList(psBlob);
+
+ // Loop through the list of power sources
+ CFIndex count = CFArrayGetCount(psList);
+ for (CFIndex i = 0; i < count; i++)
+ {
+ CFTypeRef powersource = CFArrayGetValueAtIndex(psList, i);
+ CFDictionaryRef description = IOPSGetPowerSourceDescription(psBlob, powersource);
+
+ // Skip if not present or not a battery
+ if (CFDictionaryGetValue(description, CFSTR(kIOPSIsPresentKey)) == kCFBooleanFalse || !CFStringCompare(CFDictionaryGetValue(description, CFSTR(kIOPSPowerSourceStateKey)), CFSTR(kIOPSBatteryPowerValue), 0))
+ {
+ continue;
+ }
+
+ // Check if the battery is charging atm
+ if (CFDictionaryGetValue(description, CFSTR(kIOPSIsChargingKey)) == kCFBooleanTrue)
+ {
+ CFNumberRef timeToChargeNum = CFDictionaryGetValue(description, CFSTR(kIOPSTimeToFullChargeKey));
+ int timeTilCharged = [(__bridge NSNumber *)timeToChargeNum intValue];
+
+ if (timeTilCharged > 0)
+ {
+ // Calculate the hour/minutes
+ NSInteger hour = (int)timeTilCharged / 3600;
+ NSInteger minute = (int)timeTilCharged % 3600;
+
+ // Return the time remaining string
+ self.statusItem.image = [self getBatteryIconNamed:@"BatteryCharging"];
+ self.statusItem.title = [NSString stringWithFormat:@" %ld:%02ld", hour, minute];
+ }
+ else
+ {
+ self.statusItem.image = [self getBatteryIconNamed:@"BatteryCharging"];
+ self.statusItem.title = @" Calculating…";
+ }
+ }
+ else
+ {
+ // Not charging and on a endless powersource
+ self.statusItem.image = [self getBatteryIconNamed:@"BatteryCharged"];
+ self.statusItem.title = @"";
+ }
+ }
+ }
+ // Still calculating the estimated time remaining...
+ else if (kIOPSTimeRemainingUnknown == timeRemaining)
+ {
+ self.statusItem.image = [self getBatteryIconNamed:@"BatteryEmpty"];
+ self.statusItem.title = @" Calculating…";
+ }
+ // Time is known!
+ else
+ {
+ // Calculate the hour/minutes
+ NSInteger hour = (int)timeRemaining / 3600;
+ NSInteger minute = (int)timeRemaining % 3600 / 60;
+
+ // Return the time remaining string
+ self.statusItem.image = [self getBatteryIconNamed:@"BatteryEmpty"];
+ self.statusItem.title = [NSString stringWithFormat:@" %ld:%02ld", hour, minute];
+ }
+}
+
+- (NSImage *)getBatteryIconNamed:(NSString *)iconName
{
- if (kIOPSTimeRemainingUnlimited == IOPSGetTimeRemainingEstimate()) {
- return @"Ω Unlimited Ω";
- } else if (kIOPSTimeRemainingUnknown == IOPSGetTimeRemainingEstimate()) {
- return @"Ω Calculating Ω";
- } else {
- CFTimeInterval time = IOPSGetTimeRemainingEstimate();
- NSInteger hour = (int)time / 3600;
- NSInteger minut = (int)time % 3600 / 60;
- return [NSString stringWithFormat:@"<%ld:%02ld>", hour, minut];
+ NSString *fileName = [NSString stringWithFormat:@"/System/Library/CoreServices/Menu Extras/Battery.menu/Contents/Resources/%@.pdf", iconName];
+ return [[NSImage alloc] initWithContentsOfFile:fileName];
+}
+
+- (void)toggleStartAtLogin:(id)sender
+{
+ // Check the state of start at login
+ if ([StartAtLoginHelper isInLoginItems])
+ {
+ [StartAtLoginHelper removeFromLoginItems];
+ self.startupToggle.state = NSOffState;
+ }
+ else
+ {
+ [StartAtLoginHelper addToLoginItems];
+ self.startupToggle.state = NSOnState;
}
}
View
2  Battery Time Remaining/Battery Time Remaining-Info.plist
@@ -27,7 +27,7 @@
<key>LSMinimumSystemVersion</key>
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
<key>NSHumanReadableCopyright</key>
- <string>Copyright © 2012 Han Lin Yap. All rights reserved.</string>
+ <string>Copyright © 2012 Han Lin Yap and Wrep. All rights reserved.</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
View
17 Battery Time Remaining/StartAtLoginHelper.h
@@ -0,0 +1,17 @@
+//
+// StartAtLoginHelper.h
+// Battery Time Remaining
+//
+// Created by Mathijs Kadijk on 04-08-12.
+// Copyright (c) 2012 Wrep. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@interface StartAtLoginHelper : NSObject
+
++ (BOOL)isInLoginItems;
++ (void)addToLoginItems;
++ (void)removeFromLoginItems;
+
+@end
View
138 Battery Time Remaining/StartAtLoginHelper.m
@@ -0,0 +1,138 @@
+//
+// StartAtLoginHelper.m
+// Battery Time Remaining
+//
+// Created by Mathijs Kadijk on 04-08-12.
+// Copyright (c) 2012 Wrep. All rights reserved.
+//
+
+#import "StartAtLoginHelper.h"
+
+@implementation StartAtLoginHelper
+
++ (BOOL)isInLoginItems
+{
+ BOOL isInLoginItems = NO;
+
+ // Get URL to the App
+ NSString *appPath = [[NSBundle mainBundle] bundlePath];
+ CFURLRef url = (__bridge CFURLRef)[NSURL fileURLWithPath:appPath];
+
+ // Get the current users login items
+ LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
+
+ if (loginItems)
+ {
+ // Get a array of the loginItems
+ UInt32 seedValue;
+ CFArrayRef loginItemsArrayRef = LSSharedFileListCopySnapshot(loginItems, &seedValue);
+
+ // Cast to NSArray for ease of use
+ NSArray *loginItemsArray = (__bridge NSArray *)loginItemsArrayRef;
+
+ // Loop through all loginitems
+ for (int i = 0; i < [loginItemsArray count]; i++)
+ {
+ // Get the current loginitem
+ LSSharedFileListItemRef itemRef = (__bridge LSSharedFileListItemRef)[loginItemsArray objectAtIndex:i];
+
+ // Resolve the loginitem
+ if (LSSharedFileListItemResolve(itemRef, 0, (CFURLRef *)&url, NULL) == noErr)
+ {
+ // Get the path from the URL
+ NSString *urlPath = [(__bridge NSURL *)url path];
+
+ // Check if this is us
+ if ([urlPath compare:appPath] == NSOrderedSame)
+ {
+ isInLoginItems = YES;
+ }
+ }
+
+ CFRelease(url);
+ }
+
+ CFRelease(loginItems);
+ }
+
+ return isInLoginItems;
+}
+
++ (void)addToLoginItems
+{
+ // Get URL to the App
+ NSString *appPath = [[NSBundle mainBundle] bundlePath];
+ CFURLRef url = (__bridge CFURLRef)[NSURL fileURLWithPath:appPath];
+
+ // Get the current users login items
+ LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
+
+ if (loginItems)
+ {
+ // Insert ourself into the list of startup items
+ LSSharedFileListItemRef item = LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemLast, NULL, NULL, url, NULL, NULL);
+
+ // Check if the item is inserted, if so release it
+ if (item)
+ {
+ CFRelease(item);
+ }
+ else
+ {
+ NSLog(@"Failed to insert loginitem!");
+ }
+
+ CFRelease(loginItems);
+ }
+ else
+ {
+ NSLog(@"No loginitems list found!");
+ }
+}
+
++ (void)removeFromLoginItems
+{
+ // Get URL to the App
+ NSString *appPath = [[NSBundle mainBundle] bundlePath];
+ CFURLRef url = (__bridge CFURLRef)[NSURL fileURLWithPath:appPath];
+
+ // Get the current users login items
+ LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
+
+ if (loginItems)
+ {
+ // Get a array of the loginItems
+ UInt32 seedValue;
+ CFArrayRef loginItemsArrayRef = LSSharedFileListCopySnapshot(loginItems, &seedValue);
+
+ // Cast to NSArray for ease of use
+ NSArray *loginItemsArray = (__bridge NSArray *)loginItemsArrayRef;
+
+ // Loop through all loginitems
+ for (int i = 0; i < [loginItemsArray count]; i++)
+ {
+ // Get the current loginitem
+ LSSharedFileListItemRef itemRef = (__bridge LSSharedFileListItemRef)[loginItemsArray objectAtIndex:i];
+
+ // Resolve the loginitem
+ if (LSSharedFileListItemResolve(itemRef, 0, (CFURLRef *)&url, NULL) == noErr)
+ {
+ // Get the path from the URL
+ NSString *urlPath = [(__bridge NSURL *)url path];
+
+ // Check if this is us
+ if ([urlPath compare:appPath] == NSOrderedSame)
+ {
+ // It is us, remove us from the list
+ LSSharedFileListItemRemove(loginItems, itemRef);
+ }
+ }
+
+ CFRelease(url);
+ }
+
+ CFRelease(loginItems);
+ }
+}
+
+@end
View
35 Readme.md
@@ -0,0 +1,35 @@
+Battery Time Remaining
+======================
+
+Show the estimated battery time remaining on top of your screen in Mac OS X 10.8 Mountain Lion.
+
+Why does this project exists?
+-----------------------------
+
+Apple removed the option to show the battery time remaining in the statusbar since the Mountain Lion release. This App will do exactly that, show the battery time remaining on top of your screen.
+
+How do I install it?
+--------------------
+
+Two options:
+
+- Download [version 0.2](http://cl.ly/1K3M0h1x0Z1b), unzip and run the App
+- Download the source here from Github and compile it with XCode
+
+Is it accurate?
+---------------
+
+The App shows the exact same time as you will see when you click the battery icon. The time is provided by Mac OS X itself and as accurate as you can get.
+
+How do I contribute?
+--------------------
+
+Fork this project, make some changes and submit a pull request. Check the issues tab for inspiration on what to fix. Please make sure you're fork is the latest development version!
+
+If you find any issues or have a feature request please contribute by submitting an issue here on Github!
+
+Who did make this app?
+----------------------
+
+* [codler](https://github.com/codler) / Han Lin Yap: created the [first version](https://github.com/codler/Battery-Time-Remaining) of the app
+* [mac-cain13](https://github.com/mac-cain13) / Mathijs Kadijk: made some improvements
Something went wrong with that request. Please try again.