Skip to content

Commit

Permalink
PromiseKit 2.0
Browse files Browse the repository at this point in the history
Fixes #165
Fixes #56
Closes #18
Fixes #13
  • Loading branch information
mxcl committed May 14, 2015
1 parent 894edc9 commit e96adc5
Show file tree
Hide file tree
Showing 239 changed files with 11,119 additions and 6,328 deletions.
3 changes: 3 additions & 0 deletions Cartfile.private
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
github "AliSoftware/OHHTTPStubs"
github "mxcl/Stubbilino"
github "kif-framework/KIF"
Original file line number Diff line number Diff line change
@@ -1,31 +1,30 @@
//
// AVFoundation+PromiseKit.h
// AVFoundation+AnyPromise.h
//
// Created by Matthew Loseke on 6/21/14.
//

#import <AVFoundation/AVAudioSession.h>
#import <PromiseKit/fwd.h>
#import <PromiseKit/AnyPromise.h>

/**
To import the `AVAudioSession` category:
pod "PromiseKit/AVAudioSession"
use_frameworks!
pod "PromiseKit/AVFoundation"
Or you can import all categories on `AVFoundation`:
And then in your sources:
pod "PromiseKit/AVFoundation"
#import <PromiseKit/PromiseKit.h>
*/
@interface AVAudioSession (PromiseKit)

- (PMKPromise *)promiseForRequestRecordPermission PMK_DEPRECATED("Use -requestRecordPermission");

/**
Wraps `-requestRecordPermission:`, thens the `BOOL granted` parameter
passed to the wrapped completion block. This promise cannot fail.
@see requestRecordPermission:
*/
- (PMKPromise *)requestRecordPermission;
*/
- (AnyPromise *)requestRecordPermission;

@end
21 changes: 21 additions & 0 deletions Categories/AVFoundation/AVAudioSession+AnyPromise.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// AVAudioSession+PromiseKit.m
//
// Created by Matthew Loseke on 6/21/14.
//

#import "AVAudioSession+AnyPromise.h"
#import <Foundation/Foundation.h>


@implementation AVAudioSession (PromiseKit)

- (AnyPromise *)requestRecordPermission {
return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
[[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) {
resolve(@(granted));
}];
}];
}

@end
21 changes: 21 additions & 0 deletions Categories/AVFoundation/AVAudioSession+Promise.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import AVFoundation.AVAudioSession
import Foundation
import PromiseKit

/**
To import the `AVAudioSession` category:
use_frameworks!
pod "PromiseKit/AVFoundation"
And then in your sources:
import PromiseKit
*/
extension AVAudioSession {
public func requestRecordPermission() -> Promise<Bool> {
return Promise { fulfill, _ in
requestRecordPermission(fulfill)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,26 @@
//
//

#import <PromiseKit/fwd.h>
#import <PromiseKit/AnyPromise.h>
#import <Accounts/ACAccountStore.h>

/**
To import the `ACAccountStore` category:
pod "PromiseKit/ACAccountStore"
Or you can import all categories on `Accounts`:
use_frameworks!
pod "PromiseKit/Accounts"
And then in your sources:
#import <PromiseKit/PromiseKit.h>
*/
@interface ACAccountStore (PromiseKit)

/**
Obtains permission to access protected user properties.
@param accountType The account type.
@param options Can be nil.
@return A promise that resolves when the requested permissions have been
Expand All @@ -30,7 +32,7 @@
@see requestAccessToAccountsWithType:options:completion:
*/
- (PMKPromise *)requestAccessToAccountsWithType:(ACAccountType *)type options:(NSDictionary *)options;
- (AnyPromise *)requestAccessToAccountsWithType:(ACAccountType *)type options:(NSDictionary *)options;

/**
Renews account credentials when the credentials are no longer valid.
Expand All @@ -39,7 +41,7 @@
@return A promise that thens the `ACAccountCredentialRenewResult`.
*/
- (PMKPromise *)renewCredentialsForAccount:(ACAccount *)account;
- (AnyPromise *)renewCredentialsForAccount:(ACAccount *)account;

/**
Saves an account to the Accounts database.
Expand All @@ -49,7 +51,7 @@
@return A promise that resolves when the account has been successfully
saved.
*/
- (PMKPromise *)saveAccount:(ACAccount *)account;
- (AnyPromise *)saveAccount:(ACAccount *)account;

/**
Removes an account from the account store.
Expand All @@ -59,14 +61,6 @@
@return A promise that resolves when the account has been successfully
removed.
*/
- (PMKPromise *)removeAccount:(ACAccount *)account;


#pragma mark Deprecated

- (PMKPromise *)promiseForAccountsWithType:(ACAccountType *)type options:(NSDictionary *)options PMK_DEPRECATED("Use -requestAccessToAccountsWithType:options:");
- (PMKPromise *)promiseForCredentialsRenewalWithAccount:(ACAccount *)account PMK_DEPRECATED("Use -renewCredentialsForAccount:");
- (PMKPromise *)promiseForAccountSave:(ACAccount *)account PMK_DEPRECATED("Use -saveAccount:");
- (PMKPromise *)promiseForAccountRemoval:(ACAccount *)account PMK_DEPRECATED("Use -removeAccount:");
- (AnyPromise *)removeAccount:(ACAccount *)account;

@end
48 changes: 48 additions & 0 deletions Categories/Accounts/ACAccountStore+AnyPromise.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#import "ACAccountStore+AnyPromise.h"
#import <PromiseKit/PromiseKit.h>


@implementation ACAccountStore (PromiseKit)

- (AnyPromise *)requestAccessToAccountsWithType:(ACAccountType *)type options:(NSDictionary *)options {
return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
[self requestAccessToAccountsWithType:type options:options completion:^(BOOL granted, NSError *error) {
if (granted) {
resolve([self accountsWithAccountType:type]);
} else if (error) {
resolve(error);
} else {
error = [NSError errorWithDomain:PMKErrorDomain code:PMKAccessDeniedError userInfo:@{
NSLocalizedDescriptionKey: @"Access to the requested social service has been denied. Please enable access in your device settings."
}];
resolve(error);
}
}];
}];
}

- (AnyPromise *)renewCredentialsForAccount:(ACAccount *)account {
return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
[self renewCredentialsForAccount:account completion:^(ACAccountCredentialRenewResult renewResult, NSError *error) {
resolve(error ?: @(renewResult));
}];
}];
}

- (AnyPromise *)saveAccount:(ACAccount *)account {
return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
[self saveAccount:account withCompletionHandler:^(BOOL success, NSError *error) {
resolve(error);
}];
}];
}

- (AnyPromise *)removeAccount:(ACAccount *)account {
return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
[self removeAccount:account withCompletionHandler:^(BOOL success, NSError *error) {
resolve(error);
}];
}];
}

@end
41 changes: 41 additions & 0 deletions Categories/Accounts/ACAccountStore+Promise.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import Accounts
import PromiseKit

/**
To import the `ACAccountStore` category:
use_frameworks!
pod "PromiseKit/ACAccountStore"
And then in your sources:
import PromiseKit
*/
extension ACAccountStore {
public func renewCredentialsForAccount(account: ACAccount) -> Promise<ACAccountCredentialRenewResult> {
return Promise { renewCredentialsForAccount(account, completion: $0.resolve) }
}

public func requestAccessToAccountsWithType(type: ACAccountType, options: [String: AnyObject]? = nil) -> Promise<Void> {
return Promise<Void> { fulfill, reject in
requestAccessToAccountsWithType(type, options: options, completion: { granted, error in
if granted {
fulfill()
} else if error != nil {
reject(error)
} else {
let error = NSError(domain: PMKErrorDomain, code: PMKAccessDeniedError, userInfo:[NSLocalizedDescriptionKey: "Access to the requested social service has been denied. Please enable access in your device settings."])
reject(error)
}
})
}
}

public func saveAccount(account: ACAccount) -> Promise<Void> {
return Promise<Bool> { saveAccount(account, withCompletionHandler: $0.resolve) }.asVoid()
}

public func removeAccount(account: ACAccount) -> Promise<Void> {
return Promise<Bool> { removeAccount(account, withCompletionHandler: $0.resolve) }.asVoid()
}
}
84 changes: 84 additions & 0 deletions Categories/AddressBook/ABAddressBookRequestAccess+Promise.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import AddressBook
import CoreFoundation
import Foundation.NSError
import PromiseKit

/**
Requests access to the address book.
To import `ABAddressBookRequestAccess`:
use_frameworks!
pod "PromiseKit/AddressBook"
And then in your sources:
import PromiseKit
@return A promise that fulfills with the ABAuthorizationStatus.
*/
public func ABAddressBookRequestAccess() -> Promise<ABAuthorizationStatus> {
return ABAddressBookRequestAccess().then(on: zalgo) { (_, _) -> ABAuthorizationStatus in
return ABAddressBookGetAuthorizationStatus()
}
}

/**
Requests access to the address book.
To import `ABAddressBookRequestAccess`:
pod "PromiseKit/AddressBook"
And then in your sources:
import PromiseKit
@return A promise that fulfills with the ABAddressBook instance if access was granted.
*/
public func ABAddressBookRequestAccess() -> Promise<ABAddressBook> {
return ABAddressBookRequestAccess().then(on: zalgo) { (granted, book) -> Promise<ABAddressBook> in
if granted {
return Promise(book)
} else {
switch ABAddressBookGetAuthorizationStatus() {
case .NotDetermined:
return Promise(error: "Access to the address book could not be determined.")
case .Restricted:
return Promise(error: "A head of family must grant address book access.")
case .Denied:
return Promise(error: "Address book access has been denied.")
case .Authorized:
return Promise(book) // shouldn’t be possible
}
}
}
}

extension NSError {
private convenience init(CFError error: CoreFoundation.CFError) {
let domain = CFErrorGetDomain(error) as String
let code = CFErrorGetCode(error)
let info = CFErrorCopyUserInfo(error) as [NSObject: AnyObject]
self.init(domain: domain, code: code, userInfo: info)
}
}

private func ABAddressBookRequestAccess() -> Promise<(Bool, ABAddressBook)> {
var error: Unmanaged<CFError>? = nil
let ubook = ABAddressBookCreateWithOptions(nil, &error)
if ubook != nil {
let book: ABAddressBook = ubook.takeRetainedValue()
return Promise { fulfill, reject in
ABAddressBookRequestAccessWithCompletion(book) { granted, error in
if error == nil {
fulfill(granted, book)
} else {
reject(NSError(CFError: error))
}
}
}
} else {
return Promise(NSError(CFError: error!.takeRetainedValue()))
}
}
45 changes: 45 additions & 0 deletions Categories/AssetsLibrary/ALAssetsLibrary+Promise.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import AssetsLibrary
import Foundation.NSData
import PromiseKit
import UIKit.UIViewController

/**
To import this `UIViewController` extension:
use_frameworks!
pod "PromiseKit/AssetsLibrary"
And then in your sources:
import PromiseKit
*/
extension UIViewController {
/**
@return A promise that presents the provided UIImagePickerController and
fulfills with the user selected media’s `NSData`.
*/
public func promiseViewController(vc: UIImagePickerController, animated: Bool = false, completion: (() -> Void)? = nil) -> Promise<NSData> {
let proxy = UIImagePickerControllerProxy()
vc.delegate = proxy

presentViewController(vc, animated: animated, completion: completion)

return proxy.promise.then(on: zalgo) { info -> Promise<NSData> in
let url = info[UIImagePickerControllerReferenceURL] as! NSURL

return Promise { sealant in
ALAssetsLibrary().assetForURL(url, resultBlock: { asset in
let N = Int(asset.defaultRepresentation().size())
let bytes = UnsafeMutablePointer<UInt8>.alloc(N)
var error: NSError?
asset.defaultRepresentation().getBytes(bytes, fromOffset: 0, length: N, error: &error)

sealant.resolve(NSData(bytesNoCopy: bytes, length: N), error as NSError!)

}, failureBlock: sealant.resolve)
}
}.finally {
self.dismissViewControllerAnimated(animated, completion: nil)
}
}
}
Loading

0 comments on commit e96adc5

Please sign in to comment.