Commit c6a0ceef by Brent Gulanowski

Merge pull request #203 from Shopify/task/advanced-sample

Update Advanced Sample to use new API
parents 6f4e73db 402cbea2
......@@ -42,7 +42,6 @@
847612A11CAB05BE00AB17AA /* UIFont+Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = 8476129D1CAB05BE00AB17AA /* UIFont+Additions.m */; };
847612A21CAB05BE00AB17AA /* UIImage+Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = 8476129F1CAB05BE00AB17AA /* UIImage+Additions.m */; };
84BA52EE1CB2E83C00AB1560 /* NavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 84BA52ED1CB2E83C00AB1560 /* NavigationController.m */; };
902C9B8C1BB06BF300FC456E /* GetShopOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 902C9B8B1BB06BF300FC456E /* GetShopOperation.m */; };
902C9B8F1BB0729F00FC456E /* ShippingRateTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 902C9B8E1BB0729F00FC456E /* ShippingRateTableViewCell.m */; };
902C9B921BB08FF500FC456E /* SummaryItemsTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 902C9B911BB08FF500FC456E /* SummaryItemsTableViewCell.m */; };
9079F5F41BB1AAA100CB1B35 /* CollectionListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9079F5F31BB1AAA100CB1B35 /* CollectionListViewController.m */; };
......@@ -59,11 +58,9 @@
BE8B82571B8CF49D00E3F871 /* ProductListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BE8B82561B8CF49D00E3F871 /* ProductListViewController.m */; };
BE8B825D1B8CF49D00E3F871 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BE8B825B1B8CF49D00E3F871 /* Main.storyboard */; };
BE8B82621B8CF49D00E3F871 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = BE8B82601B8CF49D00E3F871 /* LaunchScreen.xib */; };
BE8B827B1B8CFF0E00E3F871 /* GetShippingRatesOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = BE8B827A1B8CFF0E00E3F871 /* GetShippingRatesOperation.m */; };
BE8B82921B8E612700E3F871 /* ShippingRatesTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BE8B82911B8E612700E3F871 /* ShippingRatesTableViewController.m */; };
BE8B82951B8E65D700E3F871 /* PreCheckoutViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BE8B82941B8E65D700E3F871 /* PreCheckoutViewController.m */; };
BE8B829A1B8E72CC00E3F871 /* CheckoutViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BE8B82991B8E72CC00E3F871 /* CheckoutViewController.m */; };
BE948D491B9500DC009AB20B /* GetCompletionStatusOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = BE948D481B9500DC009AB20B /* GetCompletionStatusOperation.m */; };
BE948D4D1B95087A009AB20B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BE948D4C1B95087A009AB20B /* Images.xcassets */; };
/* End PBXBuildFile section */
......@@ -189,8 +186,6 @@
8476129F1CAB05BE00AB17AA /* UIImage+Additions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Additions.m"; sourceTree = "<group>"; };
84BA52EC1CB2E83C00AB1560 /* NavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NavigationController.h; sourceTree = "<group>"; };
84BA52ED1CB2E83C00AB1560 /* NavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NavigationController.m; sourceTree = "<group>"; };
902C9B8A1BB06BF300FC456E /* GetShopOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetShopOperation.h; sourceTree = "<group>"; };
902C9B8B1BB06BF300FC456E /* GetShopOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GetShopOperation.m; sourceTree = "<group>"; };
902C9B8D1BB0729F00FC456E /* ShippingRateTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = ShippingRateTableViewCell.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
902C9B8E1BB0729F00FC456E /* ShippingRateTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ShippingRateTableViewCell.m; sourceTree = "<group>"; };
902C9B901BB08FF500FC456E /* SummaryItemsTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SummaryItemsTableViewCell.h; sourceTree = "<group>"; };
......@@ -219,16 +214,12 @@
BE8B82561B8CF49D00E3F871 /* ProductListViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ProductListViewController.m; sourceTree = "<group>"; };
BE8B825C1B8CF49D00E3F871 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
BE8B82611B8CF49D00E3F871 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
BE8B82791B8CFF0E00E3F871 /* GetShippingRatesOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetShippingRatesOperation.h; sourceTree = "<group>"; };
BE8B827A1B8CFF0E00E3F871 /* GetShippingRatesOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GetShippingRatesOperation.m; sourceTree = "<group>"; };
BE8B82901B8E612700E3F871 /* ShippingRatesTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = ShippingRatesTableViewController.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
BE8B82911B8E612700E3F871 /* ShippingRatesTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ShippingRatesTableViewController.m; sourceTree = "<group>"; };
BE8B82931B8E65D700E3F871 /* PreCheckoutViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = PreCheckoutViewController.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
BE8B82941B8E65D700E3F871 /* PreCheckoutViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PreCheckoutViewController.m; sourceTree = "<group>"; };
BE8B82981B8E72CC00E3F871 /* CheckoutViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = CheckoutViewController.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
BE8B82991B8E72CC00E3F871 /* CheckoutViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CheckoutViewController.m; sourceTree = "<group>"; };
BE948D471B9500DC009AB20B /* GetCompletionStatusOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetCompletionStatusOperation.h; sourceTree = "<group>"; };
BE948D481B9500DC009AB20B /* GetCompletionStatusOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GetCompletionStatusOperation.m; sourceTree = "<group>"; };
BE948D4C1B95087A009AB20B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
/* End PBXFileReference section */
......@@ -418,7 +409,6 @@
BE8B82601B8CF49D00E3F871 /* LaunchScreen.xib */,
BE8B825B1B8CF49D00E3F871 /* Main.storyboard */,
BE5E28451B94F5C300D2ECB5 /* Mobile Buy SDK Advanced Sample.entitlements */,
BE8B82971B8E6A7100E3F871 /* Operations */,
8476122E1CAB047600AB17AA /* Product View */,
BE8B824E1B8CF49D00E3F871 /* Supporting Files */,
847612991CAB05BE00AB17AA /* UIKit Additions */,
......@@ -454,19 +444,6 @@
name = "View Controllers";
sourceTree = "<group>";
};
BE8B82971B8E6A7100E3F871 /* Operations */ = {
isa = PBXGroup;
children = (
BE8B82791B8CFF0E00E3F871 /* GetShippingRatesOperation.h */,
BE8B827A1B8CFF0E00E3F871 /* GetShippingRatesOperation.m */,
BE948D471B9500DC009AB20B /* GetCompletionStatusOperation.h */,
BE948D481B9500DC009AB20B /* GetCompletionStatusOperation.m */,
902C9B8A1BB06BF300FC456E /* GetShopOperation.h */,
902C9B8B1BB06BF300FC456E /* GetShopOperation.m */,
);
name = Operations;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
......@@ -577,7 +554,6 @@
buildActionMask = 2147483647;
files = (
847612A11CAB05BE00AB17AA /* UIFont+Additions.m in Sources */,
BE948D491B9500DC009AB20B /* GetCompletionStatusOperation.m in Sources */,
8476127B1CAB047600AB17AA /* HeaderBackgroundView.m in Sources */,
BE8B82951B8E65D700E3F871 /* PreCheckoutViewController.m in Sources */,
8476127F1CAB047600AB17AA /* OptionSelectionViewController.m in Sources */,
......@@ -597,7 +573,6 @@
847612781CAB047600AB17AA /* ProductViewController.m in Sources */,
8476126A1CAB047600AB17AA /* VisualEffectView.m in Sources */,
847612721CAB047600AB17AA /* ProductViewPresentationController.m in Sources */,
902C9B8C1BB06BF300FC456E /* GetShopOperation.m in Sources */,
847612731CAB047600AB17AA /* ProductDescriptionCell.m in Sources */,
8476126C1CAB047600AB17AA /* ActionableFooterView.m in Sources */,
902C9B8F1BB0729F00FC456E /* ShippingRateTableViewCell.m in Sources */,
......@@ -616,7 +591,6 @@
847612771CAB047600AB17AA /* ProductView.m in Sources */,
9079F5F41BB1AAA100CB1B35 /* CollectionListViewController.m in Sources */,
BE8B82541B8CF49D00E3F871 /* AppDelegate.m in Sources */,
BE8B827B1B8CFF0E00E3F871 /* GetShippingRatesOperation.m in Sources */,
842799661CB31498003AD0CE /* PaymentViewController.m in Sources */,
847612671CAB047600AB17AA /* DisclosureIndicatorView.m in Sources */,
BE8B82571B8CF49D00E3F871 /* ProductListViewController.m in Sources */,
......
......@@ -24,22 +24,22 @@
// THE SOFTWARE.
//
#import <Buy/Buy.h>
@import Buy;
#import "CheckoutViewController.h"
#import "GetCompletionStatusOperation.h"
#import "SummaryItemsTableViewCell.h"
#import "UIButton+PaymentButton.h"
NSString * const CheckoutCallbackNotification = @"CheckoutCallbackNotification";
NSString * const MerchantId = @"";
@interface CheckoutViewController () <GetCompletionStatusOperationDelegate, SFSafariViewControllerDelegate, PKPaymentAuthorizationViewControllerDelegate>
@interface CheckoutViewController () <SFSafariViewControllerDelegate, PKPaymentAuthorizationViewControllerDelegate>
@property (nonatomic, strong) BUYCheckout *checkout;
@property (nonatomic, strong) BUYClient *client;
@property (nonatomic, strong) BUYShop *shop;
@property (nonatomic, strong) NSArray *summaryItems;
@property (nonatomic, strong) BUYApplePayHelpers *applePayHelper;
@property (nonatomic, strong) BUYApplePayAuthorizationDelegate *applePayHelper;
@end
......@@ -139,22 +139,15 @@ NSString * const MerchantId = @"";
- (void)addCreditCardToCheckout:(void (^)(BOOL success, id<BUYPaymentToken> token))callback
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
[self.client storeCreditCard:[self creditCard] checkout:self.checkout completion:^(BUYCheckout *checkout, id<BUYPaymentToken> token, NSError *error) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
if (error == nil && checkout) {
[self.client storeCreditCard:[self creditCard] checkout:self.checkout completion:^(id<BUYPaymentToken> token, NSError *error) {
if (error == nil && token) {
NSLog(@"Successfully added credit card to checkout");
self.checkout = checkout;
}
else {
NSLog(@"Error applying credit card: %@", error);
}
callback(error == nil && checkout, token);
callback(error == nil && token, token);
}];
}
......@@ -203,32 +196,23 @@ NSString * const MerchantId = @"";
}];
}
#pragma mark Native Checkout
#pragma mark - Native Checkout
- (void)checkoutWithCreditCard
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
__weak CheckoutViewController *welf = self;
// First, the credit card must be stored on the checkout
[self addCreditCardToCheckout:^(BOOL success, id<BUYPaymentToken> token) {
if (success) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
// Upon successfully adding the credit card to the checkout, complete checkout must be called immediately
[welf.client completeCheckout:welf.checkout paymentToken:token completion:^(BUYCheckout *checkout, NSError *error) {
[welf.client completeCheckoutWithToken:welf.checkout.token paymentToken:token completion:^(BUYCheckout *checkout, NSError *error) {
if (error == nil && checkout) {
NSLog(@"Successfully completed checkout");
welf.checkout = checkout;
GetCompletionStatusOperation *completionOperation = [[GetCompletionStatusOperation alloc] initWithClient:welf.client withCheckout:welf.checkout];
completionOperation.delegate = welf;
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
[[NSOperationQueue mainQueue] addOperation:completionOperation];
}
else {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
......@@ -239,22 +223,6 @@ NSString * const MerchantId = @"";
}];
}
- (void)operation:(GetCompletionStatusOperation *)operation didReceiveCompletionStatus:(BUYStatus)completionStatus
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(@"Successfully got completion status: %lu", (unsigned long)completionStatus);
[self getCompletedCheckout:NULL];
}
- (void)operation:(GetCompletionStatusOperation *)operation failedToReceiveCompletionStatus:(NSError *)error
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(@"Error getting completion status: %@", error);
}
#pragma mark - Apple Pay Checkout
- (void)checkoutWithApplePay
......@@ -263,7 +231,7 @@ NSString * const MerchantId = @"";
PKPaymentAuthorizationViewController *paymentController = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest:request];
self.applePayHelper = [[BUYApplePayHelpers alloc] initWithClient:self.client checkout:self.checkout shop:self.shop];
self.applePayHelper = [[BUYApplePayAuthorizationDelegate alloc] initWithClient:self.client checkout:self.checkout shopName:self.shop.name];
paymentController.delegate = self;
/**
......@@ -404,7 +372,7 @@ NSString * const MerchantId = @"";
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
[self.client getCheckout:self.checkout completion:^(BUYCheckout *checkout, NSError *error) {
[self.client getCheckoutWithToken:self.checkout.token completion:^(BUYCheckout *checkout, NSError *error) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
......
......@@ -54,7 +54,7 @@
appId:APP_ID];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
[self.client getCollections:^(NSArray *collections, NSError *error) {
[self.client getCollectionsPage:1 completion:^(NSArray *collections, NSUInteger page, BOOL reachedEnd, NSError *error) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
if (error == nil && collections) {
......
//
// GetCompletionStatusOperation.h
// Mobile Buy SDK Advanced Sample
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import <Foundation/Foundation.h>
@import Buy;
@class GetCompletionStatusOperation;
@protocol GetCompletionStatusOperationDelegate <NSObject>
- (void)operation:(GetCompletionStatusOperation *)operation didReceiveCompletionStatus:(BUYStatus)completionStatus;
- (void)operation:(GetCompletionStatusOperation *)operation failedToReceiveCompletionStatus:(NSError *)error;
@end
@interface GetCompletionStatusOperation : NSOperation
- (instancetype)initWithClient:(BUYClient *)client withCheckout:(BUYCheckout *)checkout;
@property (nonatomic, weak) id <GetCompletionStatusOperationDelegate> delegate;
@property (nonatomic, readonly) BUYStatus completionStatus;
@end
//
// GetCompletionStatusOperation.m
// Mobile Buy SDK Advanced Sample
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import "GetCompletionStatusOperation.h"
@interface GetCompletionStatusOperation ()
@property (nonatomic, strong) BUYCheckout *checkout;
@property (nonatomic, strong) BUYClient *client;
@property (nonatomic, assign) BOOL done;
@property (nonatomic, strong) NSURLSessionDataTask *task;
@property (nonatomic) BUYStatus completionStatus;
@end
@implementation GetCompletionStatusOperation
- (instancetype)initWithClient:(BUYClient *)client withCheckout:(BUYCheckout *)checkout;
{
NSParameterAssert(client);
NSParameterAssert(checkout);
self = [super init];
if (self) {
self.checkout = checkout;
self.client = client;
}
return self;
}
- (BOOL)isFinished
{
return [super isFinished] && self.done;
}
- (void)cancel
{
[self.task cancel];
[super cancel];
}
- (void)main
{
[self pollForCompletionStatus];
}
- (void)pollForCompletionStatus
{
__block BUYStatus completionStatus = BUYStatusUnknown;
if (self.isCancelled) {
return;
}
self.task = [self.client getCompletionStatusOfCheckout:self.checkout completion:^(BUYStatus status, NSError *error) {
completionStatus = status;
if (status == BUYStatusProcessing) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self pollForCompletionStatus];
});
}
else {
self.completionStatus = status;
[self willChangeValueForKey:@"isFinished"];
self.done = YES;
[self didChangeValueForKey:@"isFinished"];
if (error) {
[self.delegate operation:self failedToReceiveCompletionStatus:error];
}
else {
[self.delegate operation:self didReceiveCompletionStatus:status];
}
}
}];
}
@end
//
// GetShippingRatesOperations.h
// Mobile Buy SDK Advanced Sample
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import <Foundation/Foundation.h>
@class BUYCheckout;
@class BUYClient;
@class GetShippingRatesOperation;
@protocol GetShippingRatesOperationDelegate <NSObject>
- (void)operation:(GetShippingRatesOperation *)operation didReceiveShippingRates:(NSArray *)shippingRates;
- (void)operation:(GetShippingRatesOperation *)operation failedToReceiveShippingRates:(NSError *)error;
@end
@interface GetShippingRatesOperation : NSOperation
- (instancetype)initWithClient:(BUYClient *)client withCheckout:(BUYCheckout *)checkout;
@property (nonatomic, weak) id <GetShippingRatesOperationDelegate> delegate;
@property (nonatomic, strong, readonly) BUYCheckout *checkout;
@property (nonatomic, strong, readonly) NSArray *shippingRates;
@end
//
// GetShippingRatesOperations.m
// Mobile Buy SDK Advanced Sample
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import "GetShippingRatesOperation.h"
@import Buy;
@interface GetShippingRatesOperation ()
@property (nonatomic, strong) BUYCheckout *checkout;
@property (nonatomic, strong) BUYClient *client;
@property (nonatomic, assign) BOOL done;
@property (nonatomic, strong) NSURLSessionDataTask *task;
@property (nonatomic, strong) NSArray *shippingRates;
@end
@implementation GetShippingRatesOperation
- (instancetype)initWithClient:(BUYClient *)client withCheckout:(BUYCheckout *)checkout;
{
NSParameterAssert(client);
NSParameterAssert(checkout);
self = [super init];
if (self) {
self.checkout = checkout;
self.client = client;
}
return self;
}
- (BOOL)isFinished
{
return [super isFinished] && self.done;
}
- (void)cancel
{
[self.task cancel];
[super cancel];
}
- (void)main
{
// We're now fetching the rates from Shopify. This will will calculate shipping rates very similarly to how our web checkout.
// We then turn our BUYShippingRate objects into PKShippingMethods for Apple to present to the user.
if ([self.checkout requiresShipping] == NO) {
[self willChangeValueForKey:@"isFinished"];
self.done = YES;
[self didChangeValueForKey:@"isFinished"];
[self.delegate operation:self didReceiveShippingRates:nil];
}
else {
[self pollForShippingRates];
}
}
- (void)pollForShippingRates
{
__block BUYStatus shippingStatus = BUYStatusUnknown;
self.task = [self.client getShippingRatesForCheckout:self.checkout completion:^(NSArray *shippingRates, BUYStatus status, NSError *error) {
shippingStatus = status;
if (error) {
[self willChangeValueForKey:@"isFinished"];
self.done = YES;
[self didChangeValueForKey:@"isFinished"];
[self.delegate operation:self failedToReceiveShippingRates:error];
}
else if (shippingStatus == BUYStatusComplete) {
self.shippingRates = shippingRates;
[self willChangeValueForKey:@"isFinished"];
self.done = YES;
[self didChangeValueForKey:@"isFinished"];
[self.delegate operation:self didReceiveShippingRates:self.shippingRates];
}
else if (shippingStatus == BUYStatusProcessing) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self pollForShippingRates];
});
}
}];
}
@end
//
// GetShopOperation.h
// Mobile Buy SDK Advanced Sample
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
@import Foundation;
@import Buy;
@class GetShopOperation;
@protocol GetShopOperationDelegate <NSObject>
- (void)operation:(GetShopOperation *)operation didReceiveShop:(BUYShop*)shop;
- (void)operation:(GetShopOperation *)operation failedToReceiveShop:(NSError *)error;
@end
@interface GetShopOperation : NSOperation
- (instancetype)initWithClient:(BUYClient *)client;
@property (nonatomic, weak) id <GetShopOperationDelegate> delegate;
@end
//
// GetShopOperation.h
// Mobile Buy SDK Advanced Sample
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import "GetShopOperation.h"
@interface GetShopOperation ()
@property (nonatomic, strong) BUYClient *client;
@property (nonatomic, assign) BOOL done;
@property (nonatomic, strong) NSURLSessionDataTask *task;
@end
@implementation GetShopOperation
- (instancetype)initWithClient:(BUYClient *)client
{
NSParameterAssert(client);
self = [super init];
if (self) {
self.client = client;
}
return self;
}
- (BOOL)isFinished
{
return [super isFinished] && self.done;
}
- (void)cancel
{
[self.task cancel];
[super cancel];
}
- (void)main
{
if (self.isCancelled) {
return;
}
self.task = [self.client getShop:^(BUYShop *shop, NSError *error) {
[self willChangeValueForKey:@"isFinished"];
self.done = YES;
[self didChangeValueForKey:@"isFinished"];
if (error) {
[self.delegate operation:self failedToReceiveShop:error];
}
else {
[self.delegate operation:self didReceiveShop:shop ];
}
}];
}
@end
......@@ -237,7 +237,7 @@ typedef NS_ENUM(NSInteger, UITableViewDiscountGiftCardSection) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
[self.client applyGiftCardWithCode:[alertController.textFields[0] text] toCheckout:self.checkout completion:^(BUYCheckout *checkout, NSError *error) {
[self.client applyGiftCardCode:[alertController.textFields[0] text] toCheckout:self.checkout completion:^(BUYCheckout *checkout, NSError *error) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
......
......@@ -56,15 +56,6 @@
- (instancetype)initWithClient:(BUYClient *)client cart:(BUYCart *)cart;
/**
* Loads the product details
*
* @param productId the product ID for the item to display
* @param completion a block to be called on completion of the loading of the product details. Will be called on the main thread.
* Upon success, the view controller should be presented modally
*/
- (void)loadProduct:(NSString *)productId completion:(void (^)(BOOL success, NSError *error))completion;
/**
* Alternative method when setting the product (and optionally, shop) directly on the view controller
*
* @param product the product to display
......
......@@ -64,10 +64,8 @@ CGFloat const BUYMaxProductViewHeight = 640.0;
@property (nonatomic, assign) BOOL shouldEnableVariantSelection;
@property (nonatomic, assign) BOOL shouldShowDescription;
@property (nonatomic, strong) BUYProduct *product;
@property (nonatomic, assign) BOOL isLoading;
@property (nonatomic, strong) NSNumberFormatter *currencyFormatter;
@property (nonatomic, weak) BUYCart *cart;
@property (nonatomic, assign) BOOL isLoadingShop;
// views
@property (nonatomic, strong) ProductView *productView;
......@@ -154,37 +152,6 @@ CGFloat const BUYMaxProductViewHeight = 640.0;
self.view.backgroundColor = [UIColor whiteColor];
}
- (ProductView *)productView
{
if (_productView == nil && self.product != nil && self.shop != nil) {
_productView = [[ProductView alloc] initWithFrame:CGRectMake(0, 0, self.preferredContentSize.width, self.preferredContentSize.height) product:self.product shouldShowApplePaySetup:self.shouldShowApplePaySetup];
_productView.translatesAutoresizingMaskIntoConstraints = NO;
_productView.hidden = YES;
[self.view addSubview:_productView];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_productView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_productView)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_productView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_productView)]];
_productView.tableView.delegate = self;
_productView.tableView.dataSource = self;
[_productView.productViewFooter setApplePayAvailable:self.shouldShowApplePayButton requiresSetup:self.shouldShowApplePaySetup];
[_productView.productViewFooter.paymentButton addTarget:self action:@selector(checkoutWithApplePay) forControlEvents:UIControlEventTouchUpInside];
if (self.cart) {
[_productView.productViewFooter.actionButton setTitle:NSLocalizedString(@"Add to Cart", nil) forState:UIControlStateNormal];
[_productView.productViewFooter.actionButton addTarget:self action:@selector(addSelectedVariantToCart) forControlEvents:UIControlEventTouchUpInside];
}
else {
[_productView.productViewFooter.actionButton addTarget:self action:@selector(checkoutWithShopify) forControlEvents:UIControlEventTouchUpInside];
}
_productView.productViewHeader.collectionView.delegate = self;
_productView.productViewHeader.collectionView.dataSource = self;
_productView.layoutMargins = UIEdgeInsetsMake(self.productView.layoutMargins.top, self.productView.layoutMargins.left, self.bottomLayoutGuide.length, self.productView.layoutMargins.right);
}
return _productView;
}
- (CGSize)preferredContentSize
{
return CGSizeMake(MIN(BUYMaxProductViewWidth, self.view.bounds.size.width),
......@@ -246,55 +213,15 @@ CGFloat const BUYMaxProductViewHeight = 640.0;
return presentationController;
}
- (void)loadProduct:(NSString *)productId completion:(void (^)(BOOL success, NSError *error))completion
- (void)loadWithProduct:(BUYProduct *)product completion:(void (^)(BOOL success, NSError *error))completion
{
if (productId == nil) {
if (completion) {
completion(NO, [NSError errorWithDomain:BUYShopifyError code:BUYShopifyError_NoProductSpecified userInfo:nil]);
}
} else {
self.isLoading = YES;
[self getShopWithCallback:^(BOOL success, NSError *error) {
if (success) {
self.productId = productId;
[self.client getProductById:productId completion:^(BUYProduct *product, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
if (completion) {
completion(NO, error);
}
} else {
self.product = product;
if (completion) {
completion(YES, nil);
}
}
});
}];
} else {
self.isLoading = NO;
if (completion) {
completion(success, error);
}
}
}];
}
}
self.product = product;
- (void)loadWithProduct:(BUYProduct *)product completion:(void (^)(BOOL success, NSError *error))completion;
{
if (product == nil) {
completion(NO, [NSError errorWithDomain:BUYShopifyError code:BUYShopifyError_NoProductSpecified userInfo:nil]);
} else {
self.isLoading = YES;
if (self.shop == nil) {
[self getShopWithCallback:^(BOOL success, NSError *error) {
if (success) {
self.product = product;
}
if (completion) {
completion(success, error);
}
......@@ -313,37 +240,30 @@ CGFloat const BUYMaxProductViewHeight = 640.0;
- (void)getShopWithCallback:(void (^)(BOOL, NSError *))block
{
// fetch shop details for the currency and country codes
self.isLoadingShop = YES;
[self.client getShop:^(BUYShop *shop, NSError *error) {
if (error == nil) {
self.shop = shop;
[self createProductView];
}
else {
if ([self.delegate respondsToSelector:@selector(controllerFailedToStartApplePayProcess:)]) {
[self.delegate controllerFailedToStartApplePayProcess:self];
}
}
self.isLoadingShop = NO;
if (block) block((error == nil), error);
}];
}
- (void)setProduct:(BUYProduct *)product
{
self.isLoading = NO;
_product = product;
self.navigationItem.title = _product.title;
self.selectedProductVariant = [_product.variants firstObject];
self.shouldShowVariantSelector = [_product isDefaultVariant] == NO;
self.shouldEnableVariantSelection = self.shouldShowVariantSelector && [_product.variants count] > 1;
self.shouldShowDescription = ([_product.htmlDescription length] == 0) == NO;
self.productView.hidden = NO;
[self setupNavigationBarAppearance];
[self.activityIndicatorView stopAnimating];
[self setNeedsStatusBarAppearanceUpdate];
if (self.presentingViewController) {
[self.navigationController setNavigationBarHidden:NO];
......@@ -362,8 +282,39 @@ CGFloat const BUYMaxProductViewHeight = 640.0;
self.currencyFormatter = [[NSNumberFormatter alloc] init];
self.currencyFormatter.numberStyle = NSNumberFormatterCurrencyStyle;
self.currencyFormatter.currencyCode = shop.currency;
[self.productView.productViewFooter setApplePayAvailable:self.shouldShowApplePaySetup requiresSetup:self.shouldShowApplePaySetup];
[self.productView.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone];
}
- (void)createProductView
{
_productView = [[ProductView alloc] initWithFrame:CGRectMake(0, 0, self.preferredContentSize.width, self.preferredContentSize.height) product:self.product shouldShowApplePaySetup:self.shouldShowApplePaySetup];
_productView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:_productView];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_productView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_productView)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_productView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_productView)]];
_productView.tableView.delegate = self;
_productView.tableView.dataSource = self;
[_productView.productViewFooter setApplePayAvailable:self.shouldShowApplePayButton requiresSetup:self.shouldShowApplePaySetup];
[_productView.productViewFooter.paymentButton addTarget:self action:@selector(checkoutWithApplePay) forControlEvents:UIControlEventTouchUpInside];
if (self.cart) {
[_productView.productViewFooter.actionButton setTitle:NSLocalizedString(@"Add to Cart", nil) forState:UIControlStateNormal];
[_productView.productViewFooter.actionButton addTarget:self action:@selector(addSelectedVariantToCart) forControlEvents:UIControlEventTouchUpInside];
}
else {
[_productView.productViewFooter.actionButton setTitle:NSLocalizedString(@"Check Out", nil) forState:UIControlStateNormal];
[_productView.productViewFooter.actionButton addTarget:self action:@selector(checkoutWithShopify) forControlEvents:UIControlEventTouchUpInside];
}
_productView.productViewHeader.collectionView.delegate = self;
_productView.productViewHeader.collectionView.dataSource = self;
_productView.layoutMargins = UIEdgeInsetsMake(self.productView.layoutMargins.top, self.productView.layoutMargins.left, self.bottomLayoutGuide.length, self.productView.layoutMargins.right);
[_productView.productViewFooter setApplePayAvailable:self.shouldShowApplePaySetup requiresSetup:self.shouldShowApplePaySetup];
[_productView.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone];
self.navigationItem.title = _product.title;
[self setupNavigationBarAppearance];
}
#pragma mark - Table view data source
......@@ -549,9 +500,9 @@ CGFloat const BUYMaxProductViewHeight = 640.0;
- (UIStatusBarStyle)preferredStatusBarStyle
{
if (self.navigationController.navigationBar.barStyle == UIBarStyleBlack || ([self navigationBarThresholdReached] == NO && self.isLoading == NO && self.productView.productViewHeader)) {
if (self.navigationController.navigationBar.barStyle == UIBarStyleBlack || ([self navigationBarThresholdReached] == NO && self.productView.productViewHeader)) {
return UIStatusBarStyleLightContent;
} else if (self.isLoading == YES && self.navigationController.navigationBar.barStyle == UIBarStyleBlack && self.productView.productViewHeader) {
} else if (self.navigationController.navigationBar.barStyle == UIBarStyleBlack && self.productView.productViewHeader) {
return UIStatusBarStyleLightContent;
} else {
return UIStatusBarStyleDefault;
......
......@@ -70,7 +70,7 @@ static void *kObservationContext = &kObservationContext;
- (UIScrollView *)scrollView
{
UIView *view = self.topViewController.view;
UIView *view = [self.topViewController isViewLoaded] ? self.topViewController.view : nil;
if ([view isKindOfClass:[UIScrollView class]]) {
return (id)view;
} else {
......
......@@ -43,8 +43,8 @@
@property (nonatomic, strong) BUYClient *client;
@property (nonatomic, strong) BUYCollection *collection;
@property (nonatomic, strong) NSArray *products;
@property (nonatomic, strong) NSURLSessionDataTask *collectionTask;
@property (nonatomic, strong) NSURLSessionDataTask *checkoutCreationTask;
@property (nonatomic, strong) NSOperation *collectionOperation;
@property (nonatomic, strong) NSOperation *checkoutCreationOperation;
@property (nonatomic, assign) BOOL demoProductViewController;
@property (nonatomic, assign) ThemeStyle themeStyle;
......@@ -112,8 +112,8 @@
- (void)dealloc
{
[self.checkoutCreationTask cancel];
[self.collectionTask cancel];
[self.checkoutCreationOperation cancel];
[self.collectionOperation cancel];
}
- (void)presentCollectionSortOptions:(id)sender
......@@ -160,9 +160,9 @@
- (void)getCollectionWithSortOrder:(BUYCollectionSort)collectionSort
{
[self.collectionTask cancel];
[self.collectionOperation cancel];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
self.collectionTask = [self.client getProductsPage:1 inCollection:self.collection.collectionId sortOrder:collectionSort completion:^(NSArray *products, NSUInteger page, BOOL reachedEnd, NSError *error) {
self.collectionOperation = [self.client getProductsPage:1 inCollection:self.collection.identifier sortOrder:collectionSort completion:^(NSArray *products, NSUInteger page, BOOL reachedEnd, NSError *error) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
if (error == nil && products) {
......@@ -279,8 +279,8 @@
- (void)demoNativeFlowWithProduct:(BUYProduct*)product
{
if (self.checkoutCreationTask.state == NSURLSessionTaskStateRunning) {
[self.checkoutCreationTask cancel];
if (self.checkoutCreationOperation.executing) {
[self.checkoutCreationOperation cancel];
}
BUYCart *cart = [self.client.modelManager insertCartWithJSONDictionary:nil];
......@@ -296,7 +296,7 @@
self.client.urlScheme = @"advancedsample://";
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
self.checkoutCreationTask = [self.client createCheckout:checkout completion:^(BUYCheckout *checkout, NSError *error) {
self.checkoutCreationOperation = [self.client createCheckout:checkout completion:^(BUYCheckout *checkout, NSError *error) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
if (error == nil && checkout) {
......
......@@ -25,14 +25,12 @@
//
#import "ShippingRatesTableViewController.h"
#import "GetShippingRatesOperation.h"
#import "PreCheckoutViewController.h"
#import "GetShopOperation.h"
#import "ShippingRateTableViewCell.h"
@import Buy;
@interface ShippingRatesTableViewController () <GetShippingRatesOperationDelegate, GetShopOperationDelegate>
@interface ShippingRatesTableViewController ()
@property (nonatomic, strong) BUYCheckout *checkout;
@property (nonatomic, strong) BUYClient *client;
@property (nonatomic, strong) NSNumberFormatter *currencyFormatter;
......@@ -64,27 +62,47 @@
[self.tableView registerClass:[ShippingRateTableViewCell class] forCellReuseIdentifier:@"Cell"];
// Setup both operations to run
GetShopOperation *shopOperation = [[GetShopOperation alloc] initWithClient:self.client];
shopOperation.delegate = self;
[[NSOperationQueue mainQueue] addOperation:shopOperation];
GetShippingRatesOperation *shippingOperation = [[GetShippingRatesOperation alloc] initWithClient:self.client withCheckout:self.checkout];
shippingOperation.delegate = self;
[[NSOperationQueue mainQueue] addOperation:shippingOperation];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
// Ensure both operations are completed before we reload the table view
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
[self getShopAndShippingRates];
}
- (void)getShopAndShippingRates
{
[self.client getShop:^(BUYShop *shop, NSError *error) {
if (shop && !error) {
[self didGetShop:shop];
[self getShippingRates];
}
else {
NSLog(@"Failed to retrieve shop: %@", error);
}
}];
}
- (void)didGetShop:(BUYShop *)shop
{
self.currencyFormatter = [[NSNumberFormatter alloc] init];
self.currencyFormatter.numberStyle = NSNumberFormatterCurrencyStyle;
self.currencyFormatter.currencyCode = shop.currency;
}
- (void)getShippingRates
{
[self.client getShippingRatesForCheckoutWithToken:self.checkout.token completion:^(NSArray *shippingRates, BUYStatus status, NSError *error) {
if ([shippingRates count] > 0 && !error) {
[self didGetShippingRates:shippingRates];
}
else {
NSLog(@"Failed to retrieve shipping rates: %@", error);
}
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
[self.tableView reloadData];
}];
[blockOperation addDependency:shopOperation];
[blockOperation addDependency:shippingOperation];
[[NSOperationQueue mainQueue] addOperation:blockOperation];
self.allOperations = @[blockOperation, shopOperation, shippingOperation];
}
- (void)didGetShippingRates:(NSArray *)shippingRates
{
self.shippingRates = shippingRates;
[self.tableView reloadData];
}
- (void)dealloc
......@@ -128,30 +146,4 @@
}];
}
#pragma mark - Shop delegate methods
-(void)operation:(GetShopOperation *)operation didReceiveShop:(BUYShop *)shop
{
self.currencyFormatter = [[NSNumberFormatter alloc] init];
self.currencyFormatter.numberStyle = NSNumberFormatterCurrencyStyle;
self.currencyFormatter.currencyCode = shop.currency;
}
-(void)operation:(GetShopOperation *)operation failedToReceiveShop:(NSError *)error
{
NSLog(@"Failed to retrieve shop: %@", error);
}
#pragma mark - Shipping Rates delegate methods
-(void)operation:(GetShippingRatesOperation *)operation didReceiveShippingRates:(NSArray *)shippingRates
{
self.shippingRates = shippingRates;
}
-(void)operation:(GetShippingRatesOperation *)operation failedToReceiveShippingRates:(NSError *)error
{
NSLog(@"Failed to retrieve shipping rates: %@", error);
}
@end
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
901931981BC5C63400D1134E /* Buy.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 901931951BC5C62800D1134E /* Buy.framework */; };
901931991BC5C63500D1134E /* Buy.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 901931951BC5C62800D1134E /* Buy.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
90858EC91B540D1B009D19D7 /* PassKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 90858EC81B540D1B009D19D7 /* PassKit.framework */; };
BE1C4E011AE9922100E21624 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BEDC7A321AE03BA800C4B4FE /* ViewController.m */; };
BE7764D61AE5724200C74937 /* CheckoutSelectionController.m in Sources */ = {isa = PBXBuildFile; fileRef = BE7764D51AE5724200C74937 /* CheckoutSelectionController.m */; };
BE7764DB1AE5728E00C74937 /* PAYButton.m in Sources */ = {isa = PBXBuildFile; fileRef = BE7764D81AE5728E00C74937 /* PAYButton.m */; };
BE7764DC1AE5728E00C74937 /* CheckoutSelectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = BE7764DA1AE5728E00C74937 /* CheckoutSelectionView.m */; };
BE9652F41AE563CE00084408 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BE9652F31AE563CE00084408 /* WebKit.framework */; };
BEDC7A2D1AE03BA800C4B4FE /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = BEDC7A2C1AE03BA800C4B4FE /* main.m */; };
BEDC7A301AE03BA800C4B4FE /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = BEDC7A2F1AE03BA800C4B4FE /* AppDelegate.m */; };
BEDC7A361AE03BA800C4B4FE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BEDC7A341AE03BA800C4B4FE /* Main.storyboard */; };
BEDC7A381AE03BA800C4B4FE /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BEDC7A371AE03BA800C4B4FE /* Images.xcassets */; };
BEDC7A3B1AE03BA900C4B4FE /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = BEDC7A391AE03BA800C4B4FE /* LaunchScreen.xib */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
901931901BC5C62800D1134E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 901931851BC5C62700D1134E /* Mobile Buy SDK.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 90F592EC1B0D5EFE0026B382;
remoteInfo = "Mobile Buy SDK Tests";
};
901931921BC5C62800D1134E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 901931851BC5C62700D1134E /* Mobile Buy SDK.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = BE9A64281B503C2F0033E558;
remoteInfo = Buy;
};
901931941BC5C62800D1134E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 901931851BC5C62700D1134E /* Mobile Buy SDK.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 901931701BC5B9BC00D1134E;
remoteInfo = "Buy Dynamic";
};
901931961BC5C62E00D1134E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 901931851BC5C62700D1134E /* Mobile Buy SDK.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = 901930E11BC5B9BC00D1134E;
remoteInfo = "Buy Dynamic";
};
9019319A1BC5C63500D1134E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 901931851BC5C62700D1134E /* Mobile Buy SDK.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = 901930E11BC5B9BC00D1134E;
remoteInfo = "Buy Dynamic";
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
9019319C1BC5C63500D1134E /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
901931991BC5C63500D1134E /* Buy.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
901931851BC5C62700D1134E /* Mobile Buy SDK.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "Mobile Buy SDK.xcodeproj"; path = "../../Mobile Buy SDK/Mobile Buy SDK.xcodeproj"; sourceTree = "<group>"; };
90858EC81B540D1B009D19D7 /* PassKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PassKit.framework; path = System/Library/Frameworks/PassKit.framework; sourceTree = SDKROOT; };
BE7764D41AE5724200C74937 /* CheckoutSelectionController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CheckoutSelectionController.h; sourceTree = "<group>"; };
BE7764D51AE5724200C74937 /* CheckoutSelectionController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CheckoutSelectionController.m; sourceTree = "<group>"; };
BE7764D71AE5728E00C74937 /* PAYButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PAYButton.h; sourceTree = "<group>"; };
BE7764D81AE5728E00C74937 /* PAYButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PAYButton.m; sourceTree = "<group>"; };
BE7764D91AE5728E00C74937 /* CheckoutSelectionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CheckoutSelectionView.h; sourceTree = "<group>"; };
BE7764DA1AE5728E00C74937 /* CheckoutSelectionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CheckoutSelectionView.m; sourceTree = "<group>"; };
BE9572AC1AE592E70024968A /* Mobile Buy SDK Web Sample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = "Mobile Buy SDK Web Sample.entitlements"; sourceTree = "<group>"; };
BE9652F31AE563CE00084408 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };
BEDC7A271AE03BA800C4B4FE /* Mobile Buy SDK Web Sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Mobile Buy SDK Web Sample.app"; sourceTree = BUILT_PRODUCTS_DIR; };
BEDC7A2B1AE03BA800C4B4FE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
BEDC7A2C1AE03BA800C4B4FE /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = main.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
BEDC7A2E1AE03BA800C4B4FE /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = AppDelegate.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
BEDC7A2F1AE03BA800C4B4FE /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
BEDC7A311AE03BA800C4B4FE /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = ViewController.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
BEDC7A321AE03BA800C4B4FE /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
BEDC7A351AE03BA800C4B4FE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
BEDC7A371AE03BA800C4B4FE /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
BEDC7A3A1AE03BA900C4B4FE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
BEDC7A241AE03BA800C4B4FE /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
90858EC91B540D1B009D19D7 /* PassKit.framework in Frameworks */,
BE9652F41AE563CE00084408 /* WebKit.framework in Frameworks */,
901931981BC5C63400D1134E /* Buy.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
90171E981AF0294500BB73DB /* Frameworks */ = {
isa = PBXGroup;
children = (
90858EC81B540D1B009D19D7 /* PassKit.framework */,
BE9652F31AE563CE00084408 /* WebKit.framework */,
);
name = Frameworks;
path = "Shopify Checkout";
sourceTree = "<group>";
};
901931861BC5C62700D1134E /* Products */ = {
isa = PBXGroup;
children = (
901931911BC5C62800D1134E /* Mobile Buy SDK Tests.xctest */,
901931931BC5C62800D1134E /* Buy.framework */,
901931951BC5C62800D1134E /* Buy.framework */,
);
name = Products;
sourceTree = "<group>";
};
BE7764DD1AE5729200C74937 /* Payment Selection */ = {
isa = PBXGroup;
children = (
BE7764D41AE5724200C74937 /* CheckoutSelectionController.h */,
BE7764D51AE5724200C74937 /* CheckoutSelectionController.m */,
BE7764D71AE5728E00C74937 /* PAYButton.h */,
BE7764D81AE5728E00C74937 /* PAYButton.m */,
BE7764D91AE5728E00C74937 /* CheckoutSelectionView.h */,
BE7764DA1AE5728E00C74937 /* CheckoutSelectionView.m */,
);
name = "Payment Selection";
sourceTree = "<group>";
};
BEDC7A1E1AE03BA800C4B4FE = {
isa = PBXGroup;
children = (
901931851BC5C62700D1134E /* Mobile Buy SDK.xcodeproj */,
90171E981AF0294500BB73DB /* Frameworks */,
BEDC7A291AE03BA800C4B4FE /* Mobile Buy SDK Web Sample */,
BEDC7A281AE03BA800C4B4FE /* Products */,
);
sourceTree = "<group>";
};
BEDC7A281AE03BA800C4B4FE /* Products */ = {
isa = PBXGroup;
children = (
BEDC7A271AE03BA800C4B4FE /* Mobile Buy SDK Web Sample.app */,
);
name = Products;
sourceTree = "<group>";
};
BEDC7A291AE03BA800C4B4FE /* Mobile Buy SDK Web Sample */ = {
isa = PBXGroup;
children = (
BE9572AC1AE592E70024968A /* Mobile Buy SDK Web Sample.entitlements */,
BE7764DD1AE5729200C74937 /* Payment Selection */,
BEDC7A2E1AE03BA800C4B4FE /* AppDelegate.h */,
BEDC7A2F1AE03BA800C4B4FE /* AppDelegate.m */,
BEDC7A311AE03BA800C4B4FE /* ViewController.h */,
BEDC7A321AE03BA800C4B4FE /* ViewController.m */,
BEDC7A341AE03BA800C4B4FE /* Main.storyboard */,
BEDC7A371AE03BA800C4B4FE /* Images.xcassets */,
BEDC7A391AE03BA800C4B4FE /* LaunchScreen.xib */,
BEDC7A2A1AE03BA800C4B4FE /* Supporting Files */,
);
path = "Mobile Buy SDK Web Sample";
sourceTree = "<group>";
};
BEDC7A2A1AE03BA800C4B4FE /* Supporting Files */ = {
isa = PBXGroup;
children = (
BEDC7A2B1AE03BA800C4B4FE /* Info.plist */,
BEDC7A2C1AE03BA800C4B4FE /* main.m */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
BEDC7A261AE03BA800C4B4FE /* Mobile Buy SDK Web Sample */ = {
isa = PBXNativeTarget;
buildConfigurationList = BEDC7A4A1AE03BA900C4B4FE /* Build configuration list for PBXNativeTarget "Mobile Buy SDK Web Sample" */;
buildPhases = (
BEDC7A231AE03BA800C4B4FE /* Sources */,
BEDC7A241AE03BA800C4B4FE /* Frameworks */,
BEDC7A251AE03BA800C4B4FE /* Resources */,
BE9572AD1AE5BEF20024968A /* ShellScript */,
9019319C1BC5C63500D1134E /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
901931971BC5C62E00D1134E /* PBXTargetDependency */,
9019319B1BC5C63500D1134E /* PBXTargetDependency */,
);
name = "Mobile Buy SDK Web Sample";
productName = "Shopify Checkout";
productReference = BEDC7A271AE03BA800C4B4FE /* Mobile Buy SDK Web Sample.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
BEDC7A1F1AE03BA800C4B4FE /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0700;
ORGANIZATIONNAME = Shopify;
TargetAttributes = {
BEDC7A261AE03BA800C4B4FE = {
CreatedOnToolsVersion = 6.2;
SystemCapabilities = {
com.apple.OMC = {
enabled = 1;
};
com.apple.Passbook = {
enabled = 0;
};
};
};
};
};
buildConfigurationList = BEDC7A221AE03BA800C4B4FE /* Build configuration list for PBXProject "Mobile Buy SDK Web Sample" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = BEDC7A1E1AE03BA800C4B4FE;
productRefGroup = BEDC7A281AE03BA800C4B4FE /* Products */;
projectDirPath = "";
projectReferences = (
{
ProductGroup = 901931861BC5C62700D1134E /* Products */;
ProjectRef = 901931851BC5C62700D1134E /* Mobile Buy SDK.xcodeproj */;
},
);
projectRoot = "";
targets = (
BEDC7A261AE03BA800C4B4FE /* Mobile Buy SDK Web Sample */,
);
};
/* End PBXProject section */
/* Begin PBXReferenceProxy section */
901931911BC5C62800D1134E /* Mobile Buy SDK Tests.xctest */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
path = "Mobile Buy SDK Tests.xctest";
remoteRef = 901931901BC5C62800D1134E /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
901931931BC5C62800D1134E /* Buy.framework */ = {
isa = PBXReferenceProxy;
fileType = wrapper.framework;
path = Buy.framework;
remoteRef = 901931921BC5C62800D1134E /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
901931951BC5C62800D1134E /* Buy.framework */ = {
isa = PBXReferenceProxy;
fileType = wrapper.framework;
path = Buy.framework;
remoteRef = 901931941BC5C62800D1134E /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
BEDC7A251AE03BA800C4B4FE /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
BEDC7A361AE03BA800C4B4FE /* Main.storyboard in Resources */,
BEDC7A3B1AE03BA900C4B4FE /* LaunchScreen.xib in Resources */,
BEDC7A381AE03BA800C4B4FE /* Images.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
BE9572AD1AE5BEF20024968A /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "FILE=\"${SRCROOT}/HockeySDK-iOS/BuildAgent\"\nif [ -f \"$FILE\" ]; then\n\"$FILE\"\nfi";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
BEDC7A231AE03BA800C4B4FE /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
BE1C4E011AE9922100E21624 /* ViewController.m in Sources */,
BEDC7A301AE03BA800C4B4FE /* AppDelegate.m in Sources */,
BE7764D61AE5724200C74937 /* CheckoutSelectionController.m in Sources */,
BEDC7A2D1AE03BA800C4B4FE /* main.m in Sources */,
BE7764DC1AE5728E00C74937 /* CheckoutSelectionView.m in Sources */,
BE7764DB1AE5728E00C74937 /* PAYButton.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
901931971BC5C62E00D1134E /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = "Buy Dynamic";
targetProxy = 901931961BC5C62E00D1134E /* PBXContainerItemProxy */;
};
9019319B1BC5C63500D1134E /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = "Buy Dynamic";
targetProxy = 9019319A1BC5C63500D1134E /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
BEDC7A341AE03BA800C4B4FE /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
BEDC7A351AE03BA800C4B4FE /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
BEDC7A391AE03BA800C4B4FE /* LaunchScreen.xib */ = {
isa = PBXVariantGroup;
children = (
BEDC7A3A1AE03BA900C4B4FE /* Base */,
);
name = LaunchScreen.xib;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
BEDC7A481AE03BA900C4B4FE /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.2;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
BEDC7A491AE03BA900C4B4FE /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.2;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
BEDC7A4B1AE03BA900C4B4FE /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = "Mobile Buy SDK Web Sample/Mobile Buy SDK Web Sample.entitlements";
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
DEBUG_INFORMATION_FORMAT = dwarf;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"${PROJECT_DIR}/../**",
);
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"${PROJECT_DIR}/**",
"${PROJECT_DIR}/../..",
);
INFOPLIST_FILE = "Mobile Buy SDK Web Sample/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/**",
);
OTHER_LDFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = com.shopify.mobilebuysdkwebsample;
PRODUCT_NAME = "Mobile Buy SDK Web Sample";
PROVISIONING_PROFILE = "";
TARGETED_DEVICE_FAMILY = 1;
USER_HEADER_SEARCH_PATHS = "${PROJECT_DIR}/**";
};
name = Debug;
};
BEDC7A4C1AE03BA900C4B4FE /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = "Mobile Buy SDK Web Sample/Mobile Buy SDK Web Sample.entitlements";
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
DEBUG_INFORMATION_FORMAT = dwarf;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"${PROJECT_DIR}/../**",
);
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"${PROJECT_DIR}/**",
"${PROJECT_DIR}/../..",
);
INFOPLIST_FILE = "Mobile Buy SDK Web Sample/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/**",
);
OTHER_LDFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = com.shopify.mobilebuysdkwebsample;
PRODUCT_NAME = "Mobile Buy SDK Web Sample";
PROVISIONING_PROFILE = "";
TARGETED_DEVICE_FAMILY = 1;
USER_HEADER_SEARCH_PATHS = "${PROJECT_DIR}/**";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
BEDC7A221AE03BA800C4B4FE /* Build configuration list for PBXProject "Mobile Buy SDK Web Sample" */ = {
isa = XCConfigurationList;
buildConfigurations = (
BEDC7A481AE03BA900C4B4FE /* Debug */,
BEDC7A491AE03BA900C4B4FE /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
BEDC7A4A1AE03BA900C4B4FE /* Build configuration list for PBXNativeTarget "Mobile Buy SDK Web Sample" */ = {
isa = XCConfigurationList;
buildConfigurations = (
BEDC7A4B1AE03BA900C4B4FE /* Debug */,
BEDC7A4C1AE03BA900C4B4FE /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = BEDC7A1F1AE03BA800C4B4FE /* Project object */;
}
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:Shopify Checkout.xcodeproj">
</FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "BEDC7A261AE03BA800C4B4FE"
BuildableName = "Mobile Buy SDK Web Sample.app"
BlueprintName = "Mobile Buy SDK Web Sample"
ReferencedContainer = "container:Mobile Buy SDK Web Sample.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "BEDC7A261AE03BA800C4B4FE"
BuildableName = "Mobile Buy SDK Web Sample.app"
BlueprintName = "Mobile Buy SDK Web Sample"
ReferencedContainer = "container:Mobile Buy SDK Web Sample.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "BEDC7A261AE03BA800C4B4FE"
BuildableName = "Mobile Buy SDK Web Sample.app"
BlueprintName = "Mobile Buy SDK Web Sample"
ReferencedContainer = "container:Mobile Buy SDK Web Sample.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "BEDC7A261AE03BA800C4B4FE"
BuildableName = "Mobile Buy SDK Web Sample.app"
BlueprintName = "Mobile Buy SDK Web Sample"
ReferencedContainer = "container:Mobile Buy SDK Web Sample.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
//
// AppDelegate.h
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
@import UIKit;
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
//
// AppDelegate.m
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import "AppDelegate.h"
#import "ViewController.h"
@import Buy;
#warning - Enter your shop domain and API Key
#define SHOP_DOMAIN @""
#define API_KEY @""
#define CHANNEL_ID @""
#warning Optionally, to support Apple Pay, enter your merchant ID
#define MERCHANT_ID @""
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Initialize the Buy SDK
BUYClient *client = [[BUYClient alloc] initWithShopDomain:SHOP_DOMAIN
apiKey:API_KEY
channelId:CHANNEL_ID];
// Setup the views
ViewController *storeController = [[ViewController alloc] initWithClient:client];
storeController.merchantId = MERCHANT_ID;
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:storeController];
navController.toolbarHidden = NO;
navController.navigationBarHidden = NO;
navController.navigationBar.barStyle = UIStatusBarStyleLightContent;
self.window.rootViewController = navController;
[self.window makeKeyAndVisible];
return YES;
}
@end
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 Shopify. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="20" y="439" width="441" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Mobile Buy SDK Web Sample" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="20" y="140" width="441" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="548" y="455"/>
</view>
</objects>
</document>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6211" systemVersion="14A298i" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6204"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
//
// CheckoutSelectionController.h
// Checkout
//
// Created by Shopify.
// Copyright (c) 2015 Shopify. All rights reserved.
//
@import UIKit;
@class CheckoutSelectionController;
typedef NS_ENUM(NSUInteger, CheckoutType) {
CheckoutTypeNormal,
CheckoutTypeApplePay
};
@protocol CheckoutSelectionControllerDelegate <NSObject>
- (void)checkoutSelectionControllerCancelled:(CheckoutSelectionController *)controller;
- (void)checkoutSelectionController:(CheckoutSelectionController *)controller selectedCheckoutType:(CheckoutType)checkoutType;
@end
@interface CheckoutSelectionController : UIViewController
@property (nonatomic, strong) NSURLRequest *checkoutRequest;
@property (nonatomic, weak) id <CheckoutSelectionControllerDelegate> delegate;
@end
//
// CheckoutSelectionController.m
// Checkout
//
// Created by Shopify.
// Copyright (c) 2015 Shopify. All rights reserved.
//
#import "CheckoutSelectionController.h"
#import "CheckoutSelectionView.h"
#define kCheckoutAnimationTime 0.3f
@interface CheckoutSelectionController () <UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning>
@end
@implementation CheckoutSelectionController {
CheckoutSelectionView *_selectionView;
}
- (instancetype)init
{
self = [super init];
if (self) {
self.modalPresentationStyle = UIModalPresentationCustom;
self.transitioningDelegate = self;
}
return self;
}
- (void)loadView
{
UIView *background = [[UIView alloc] init];
background.backgroundColor = [UIColor clearColor];
self.view = background;
PAYButton *applePayButton = [PAYButton buttonWithType:UIButtonTypeCustom];
applePayButton.paymentImageView.image = [UIImage imageNamed:@"ApplePayMark"];
applePayButton.paymentLabel.text = @"Complete with Apple Pay";
PAYButton *checkoutButton = [PAYButton buttonWithType:UIButtonTypeCustom];
checkoutButton.paymentImageView.image = [UIImage imageNamed:@"credit"];
checkoutButton.paymentLabel.text = @"Continue Checkout";
PAYButton *cancelButton = [PAYButton buttonWithType:UIButtonTypeCustom];
cancelButton.paymentImageView.image = [UIImage imageNamed:@"cancel"];
cancelButton.paymentLabel.text = @"Cancel";
_selectionView = [[CheckoutSelectionView alloc] initWithFrame:self.view.bounds buttons:@[applePayButton, checkoutButton, cancelButton]];
_selectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:_selectionView];
[applePayButton addTarget:self action:@selector(applePayPressed:) forControlEvents:UIControlEventTouchUpInside];
[checkoutButton addTarget:self action:@selector(checkoutPressed:) forControlEvents:UIControlEventTouchUpInside];
[cancelButton addTarget:self action:@selector(cancelPressed:) forControlEvents:UIControlEventTouchUpInside];
}
#pragma mark - Button Presses
- (void)applePayPressed:(id)sender
{
[_delegate checkoutSelectionController:self selectedCheckoutType:CheckoutTypeApplePay];
}
- (void)checkoutPressed:(id)sender
{
[_delegate checkoutSelectionController:self selectedCheckoutType:CheckoutTypeNormal];
}
- (void)cancelPressed:(id)sender
{
[_delegate checkoutSelectionControllerCancelled:self];
}
#pragma mark - Transitioning Delegate Methods
- (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
{
return self;
}
- (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
{
return self;
}
#pragma mark - Animated Transitioning Methods
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
return kCheckoutAnimationTime;
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
BOOL appearing = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey] == self;
BOOL animated = [transitionContext isAnimated];
UIView *containerView = [transitionContext containerView];
self.view.frame = [containerView bounds];
self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
if (appearing) {
[containerView addSubview:self.view];
[_selectionView showButtons:animated ? kCheckoutAnimationTime : 0.0f completion:^(BOOL complete) {
[transitionContext completeTransition:YES];
}];
}
else {
[_selectionView hideButtons:animated ? kCheckoutAnimationTime : 0.0f completion:^(BOOL complete) {
[self.view removeFromSuperview];
[transitionContext completeTransition:YES];
}];
}
}
@end
//
// CheckoutSelectionView.h
// Checkout
//
// Created by Shopify.
// Copyright (c) 2015 Shopify. All rights reserved.
//
@import UIKit;
#import "PAYButton.h"
@interface CheckoutSelectionView : UIView
- (instancetype)initWithFrame:(CGRect)frame buttons:(NSArray *)buttons;
- (void)showButtons:(CGFloat)animationDuration completion:(void (^)(BOOL complete))completion;
- (void)hideButtons:(CGFloat)animationDuration completion:(void (^)(BOOL complete))completion;
@end
//
// CheckoutSelectionView.m
// Checkout
//
// Created by Shopify.
// Copyright (c) 2015 Shopify. All rights reserved.
//
#import "CheckoutSelectionView.h"
//Views
#import "PAYButton.h"
#define kSidePadding 15.0f
#define kButtonIconPadding 8.0f
#define kPaymentButtonHeight 70.0f
#define kAnimationOffset 80.0f
#define kDelay 0.10f
@implementation CheckoutSelectionView {
UIView *_background;
NSArray *_buttons;
}
- (instancetype)initWithFrame:(CGRect)frame buttons:(NSArray *)buttons
{
self = [super initWithFrame:frame];
if (self) {
_background = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
_background.alpha = 0.0f;
_background.frame = self.bounds;
_background.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self addSubview:_background];
_buttons = buttons;
for (UIButton *button in _buttons) {
[_background addSubview:button];
button.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
}
}
return self;
}
- (CGSize)sizeThatFits:(CGSize)size
{
NSUInteger buttonCount = [_buttons count];
return CGSizeMake(size.width, kPaymentButtonHeight * buttonCount + kSidePadding * (buttonCount + 1));
}
- (void)layoutButtonsAsHidden
{
CGRect bounds = _background.bounds;
CGFloat offsetX = bounds.origin.x + roundf(bounds.size.width / 2) + kSidePadding;
CGFloat offsetY = bounds.origin.y + bounds.size.height - [_buttons count] * (kPaymentButtonHeight + kSidePadding);
CGFloat width = bounds.size.width - 2 * kSidePadding;
for (UIButton *button in _buttons) {
button.frame = CGRectMake(offsetX, offsetY, width, kPaymentButtonHeight);
button.alpha = 0.0f;
offsetY += kPaymentButtonHeight + kSidePadding;
}
}
- (void)showButtons:(CGFloat)animationDuration completion:(void (^)(BOOL complete))completion
{
[self layoutButtonsAsHidden];
[UIView animateWithDuration:animationDuration delay:0.0f options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction animations:^{
_background.alpha = 1.0f;
} completion:nil];
[self animateButtonsToOffset:0.0f duration:animationDuration alpha:1.0f completion:completion];
}
- (void)hideButtons:(CGFloat)animationDuration completion:(void (^)(BOOL complete))completion
{
[UIView animateWithDuration:animationDuration delay:0.0f options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction animations:^{
_background.alpha = 0.0f;
} completion:nil];
[self animateButtonsToOffset:kAnimationOffset duration:animationDuration alpha:0.0f completion:completion];
}
- (void)animateButtonsToOffset:(CGFloat)offset duration:(CGFloat)duration alpha:(CGFloat)alpha completion:(void (^)(BOOL complete))completion
{
CGRect bounds = self.bounds;
CGSize size = [self sizeThatFits:bounds.size];
CGFloat offsetY = bounds.origin.y + bounds.size.height - size.height;
CGFloat offsetX = bounds.origin.x + kSidePadding + offset;
CGFloat delay = 0.0f;
for (UIButton *button in _buttons) {
//Animate each button independently and call the completion handler when the last button has finished animating
[UIView animateWithDuration:duration delay:delay usingSpringWithDamping:0.8f initialSpringVelocity:0.2f options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction animations:^{
button.frame = CGRectMake(offsetX, offsetY, button.frame.size.width, button.frame.size.height);
button.alpha = alpha;
} completion:button == [_buttons lastObject] ? completion : nil];
offsetY += kPaymentButtonHeight + kSidePadding;
delay += kDelay;
}
}
@end
{
"images" : [
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-Small@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-Small@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-Small-40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-Small-40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-60@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
\ No newline at end of file
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "Apple_Pay_mark_normal_@2x.png"
},
{
"idiom" : "universal",
"scale" : "3x",
"filename" : "Apple_Pay_mark_normal_@3x.png"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
\ No newline at end of file
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "back@2x.png"
},
{
"idiom" : "universal",
"scale" : "3x",
"filename" : "back@3x.png"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
\ No newline at end of file
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "forward@2x.png"
},
{
"idiom" : "universal",
"scale" : "3x",
"filename" : "forward@3x.png"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
\ No newline at end of file
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "shop.png"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "shop@2x.png"
},
{
"idiom" : "universal",
"scale" : "3x",
"filename" : "shop@3x.png"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Web Sample</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.2.2</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.in-app-payments</key>
<array/>
</dict>
</plist>
//
// PAYButton.h
// Checkout
//
// Created by Shopify.
// Copyright (c) 2015 Shopify. All rights reserved.
//
@import UIKit;
@interface PAYButton : UIButton
@property (nonatomic, strong, readonly) UIImageView *paymentImageView;
@property (nonatomic, strong, readonly) UILabel *paymentLabel;
@end
//
// PAYButton.m
// Checkout
//
// Created by Shopify.
// Copyright (c) 2015 Shopify. All rights reserved.
//
#import "PAYButton.h"
#define kButtonMargin 11.0f
#define kButtonSelectionInset 3.0f
@implementation PAYButton {
UIView *_highlightView;
UIView *_imageBackgroundView;
BOOL _animating;
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
_imageBackgroundView = [[UIView alloc] init];
_imageBackgroundView.backgroundColor = [UIColor whiteColor];
_imageBackgroundView.userInteractionEnabled = NO;
[self addSubview:_imageBackgroundView];
_paymentImageView = [[UIImageView alloc] initWithFrame:_imageBackgroundView.bounds];
_paymentImageView.contentMode = UIViewContentModeCenter;
_paymentImageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[_imageBackgroundView addSubview:_paymentImageView];
_paymentLabel = [[UILabel alloc] init];
[_paymentLabel setFont:[UIFont fontWithName:@"HelveticaNeue-Light" size:20.0f]];
[_paymentLabel setTextColor:[UIColor whiteColor]];
[self addSubview:_paymentLabel];
_highlightView = [[UIView alloc] initWithFrame:frame];
_highlightView.alpha = 0.0f;
_highlightView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
_highlightView.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.2f];
_highlightView.userInteractionEnabled = NO;
[self addSubview:_highlightView];
}
return self;
}
- (CGRect)rectForHighlightedBackground
{
CGRect bounds = self.bounds;
return CGRectMake(bounds.origin.x + kButtonSelectionInset, bounds.origin.y + kButtonSelectionInset, bounds.size.height - kButtonSelectionInset * 2.0f, bounds.size.height - kButtonSelectionInset * 2.0f);
}
- (CGRect)rectForNormalBackground
{
CGRect bounds = self.bounds;
return CGRectMake(bounds.origin.x, bounds.origin.y, bounds.size.height, bounds.size.height);
}
- (void)setButtonFrame:(CGRect)frame
{
_imageBackgroundView.frame = frame;
_highlightView.frame = _imageBackgroundView.frame;
_imageBackgroundView.layer.cornerRadius = floorf(frame.size.height / 2);
_highlightView.layer.cornerRadius = _imageBackgroundView.layer.cornerRadius;
}
- (void)setHighlighted:(BOOL)highlighted
{
if (highlighted != self.isHighlighted) {
[super setHighlighted:highlighted];
CGRect rect = highlighted ? [self rectForHighlightedBackground] : [self rectForNormalBackground];
_animating = YES;
[UIView animateWithDuration:0.1f delay:0.0f options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionAllowUserInteraction animations:^{
_highlightView.alpha = highlighted ? 1.0f : 0.0f;
_paymentLabel.textColor = highlighted ? [UIColor lightGrayColor] : [UIColor whiteColor];
[self setButtonFrame:rect];
} completion:^(BOOL finished) {
_animating = NO;
}];
}
}
- (void)layoutSubviews
{
[super layoutSubviews];
CGRect bounds = self.bounds;
if (_animating == NO) {
[self setButtonFrame:[self rectForNormalBackground]];
}
CGFloat textHeight = ceilf([[_paymentLabel attributedText] size].height);
CGFloat backgroundMaxX = CGRectGetMaxX([self rectForNormalBackground]) + kButtonMargin;
_paymentLabel.frame = CGRectMake(backgroundMaxX, bounds.origin.y + roundf((bounds.size.height - textHeight) * 0.5f), bounds.size.width - backgroundMaxX - kButtonMargin, textHeight);
}
@end
//
// ViewController.h
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
@import UIKit;
#import <Buy/Buy.h>
@interface ViewController : BUYStoreViewController
@end
//
// ViewController.m
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import "ViewController.h"
#import "CheckoutSelectionController.h"
@interface ViewController () <BUYStoreViewControllerDelegate, CheckoutSelectionControllerDelegate>
@property (nonatomic, copy) BUYCheckoutTypeBlock callback;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.delegate = self;
// Add a home button to the navigation bar
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.tintColor = [UIColor whiteColor];
UIImage *buttonImage = [UIImage imageNamed:@"shop"];
[button setImage:[buttonImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
[button setFrame:CGRectMake(0, 0, 53, 31)];
[button addTarget:self action:@selector(goHome)forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] initWithCustomView:button];
self.navigationItem.rightBarButtonItem = rightButton;
[self loadShopWithCallback:^(BOOL success, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (success) {
self.title = self.shop.name;
}
else {
NSLog(@"Error fetching shop: %@", error.localizedDescription);
}
});
}];
}
- (void)goHome
{
[self reloadHomePage];
}
#pragma mark - BUYStoreViewController delegate methods
- (void)controller:(BUYStoreViewController *)controller shouldProceedWithCheckoutType:(BUYCheckoutTypeBlock)completionHandler
{
// If ApplePay is not setup, proceed to normal checkout
if (self.isApplePayAvailable)
{
CheckoutSelectionController *selectionController = [[CheckoutSelectionController alloc] init];
selectionController.delegate = self;
self.callback = completionHandler;
[self presentViewController:selectionController animated:YES completion:nil];
}
else {
completionHandler(BUYCheckoutTypeNormal);
}
}
- (void)controller:(BUYViewController *)controller failedToCreateCheckout:(NSError *)error
{
NSLog(@"Failed to create checkout: %@", error);
}
- (void)controllerFailedToStartApplePayProcess:(BUYViewController *)controller
{
NSLog(@"Failed to start the Apple Pay process. We weren't given an error :(");
}
- (void)controller:(BUYViewController *)controller failedToUpdateCheckout:(BUYCheckout *)checkout withError:(NSError *)error
{
NSLog(@"Failed to update checkout: %@, error: %@", checkout.token, error);
}
- (void)controller:(BUYViewController *)controller failedToGetShippingRates:(BUYCheckout *)checkout withError:(NSError *)error
{
NSLog(@"Failed to get shipping rates: %@, error: %@", checkout.token, error);
}
- (void)controller:(BUYViewController *)controller failedToCompleteCheckout:(BUYCheckout *)checkout withError:(NSError *)error
{
NSLog(@"Failed to complete checkout: %@, error: %@", checkout.token, error);
}
- (void)controller:(BUYViewController *)controller didCompleteCheckout:(BUYCheckout *)checkout status:(BUYStatus)status
{
NSLog(@"Did complete checkout: %@, status: %ld", checkout.token, (unsigned long)status);
}
#pragma mark - PAYSelectionController delegate
- (void)checkoutSelectionControllerCancelled:(CheckoutSelectionController *)controller
{
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)checkoutSelectionController:(CheckoutSelectionController *)controller selectedCheckoutType:(CheckoutType)checkoutType
{
self.callback(checkoutType == CheckoutTypeApplePay ? BUYCheckoutTypeApplePay : BUYCheckoutTypeNormal);
[self dismissViewControllerAnimated:YES completion:nil];
}
@end
//
// main.m
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
@import UIKit;
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
# Mobile Buy SDK Sample Web App
The web sample app demonstrates how you can load your shop's website in a webview, and support Apple Pay.
### Getting started
First, add your shop domain, API key and Channel ID to the `AppDelegate.h` macros.
```objc
#define SHOP_DOMAIN @"<shop_domain>"
#define API_KEY @"<api_key>"
#define CHANNEL_ID @"<channel_id>"
```
To support Apple Pay, add your Merchant ID as well.
```objc
#define MERCHANT_ID @"<merchant_id>"
```
### Overview
The sample app instantiates a view controller which is a subclass of `BUYStoreViewController`. This displays a webview with your shop, but intercepts the checkout to support Apple Pay.
The sample app also demonstrates how to use the `BUYClient` to obtain shop details by calling `getShop:`
```objc
[self.provider getShop:^(BUYShop *shop, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error == nil && shop) {
self.title = shop.name;
}
else {
NSLog(@"Error fetching shop: %@", error.localizedDescription);
}
});
}];
```
......@@ -1217,7 +1217,6 @@
84DD12A91CC63FE600A2442D /* _BUYOrder.h in Headers */,
84DD129F1CC63FE600A2442D /* _BUYCustomer.h in Headers */,
9A0B0C671CEA703E0037D68F /* BUYClient+Routing.h in Headers */,
9A0B0CA81CED0A860037D68F /* BUYCheckoutOperation.h in Headers */,
84DD12991CC63FE600A2442D /* _BUYCart.h in Headers */,
84DD129D1CC63FE600A2442D /* _BUYCollection.h in Headers */,
9A0B0C731CEB52B90037D68F /* BUYClient+Checkout.h in Headers */,
......@@ -1286,6 +1285,7 @@
9032F2DB1BE9457A00BB9EEF /* BUYCheckoutAttribute.h in Headers */,
9019315E1BC5B9BC00D1134E /* BUYError.h in Headers */,
84980F371CB75C2900CFAB58 /* NSPropertyDescription+BUYAdditions.h in Headers */,
9A0B0CA81CED0A860037D68F /* BUYCheckoutOperation.h in Headers */,
901931611BC5B9BC00D1134E /* BUYClient.h in Headers */,
9A585C0B1CE6440B001F20F0 /* BUYOperation.h in Headers */,
9A0B0C791CEB5BBD0037D68F /* BUYAuthenticatedResponse.h in Headers */,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment