Commit f4be3b7b by Brent Gulanowski Committed by GitHub

Merge pull request #263 from Shopify/develop

SDK version 2.0 release
parents 572087a3 7cbf96d8
//
// BUYTheme+Additions.h
// Theme+Additions.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,52 +24,13 @@
// THE SOFTWARE.
//
#import "BUYTheme.h"
#import "BUYPaymentButton.h"
#import "Theme.h"
#define BUY_RGB(r, g, b) BUY_RGBA(r, g, b, 1)
#define BUY_RGBA(r, g, b, a) [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:a]
@interface BUYTheme (Additions)
@interface Theme (Additions)
#pragma mark - Colors
/**
* The product view background color used in various views based on the theme
*
* @return The color appropriate for the BUYThemeStyle
*/
- (UIColor*)backgroundColor;
/**
* The background color for selected table view cells based on the theme
*
* @return The color appropriate for the BUYThemeStyle
*/
- (UIColor*)selectedBackgroundColor;
/**
* The product view's table view separator color based on the theme
*
* @return The color appropriate for the BUYThemeStyle
*/
- (UIColor*)separatorColor;
/**
* The product view's table view disclosure indicator color based on the theme
*
* @return The color appropriate for the BUYThemeStyle
*/
- (UIColor*)disclosureIndicatorColor;
/**
* The Checkout button's text color based on the theme
*
* @return The color appropriate for the BUYThemeStyle
*/
- (UIColor*)checkoutButtonTextColor;
/**
* Top gradient color
*
* @return A dark color
......@@ -77,82 +38,33 @@
+ (UIColor*)topGradientViewTopColor;
/**
* The background color for the error toast view in the product view
*
* @return The color appropriate for the BUYThemeStyle
*/
- (UIColor*)errorTintOverlayColor;
/**
* The navigation bar's title color based on the theme
*
* @return The color appropriate for the BUYThemeStyle
*/
- (UIColor*)navigationBarTitleColor;
/**
* The variant selection's navigation bar's title color based on the theme
*
* @return The color appropriate for the BUYThemeStyle
*/
- (UIColor*)navigationBarTitleVariantSelectionColor;
/**
* The color for the product title text
*
* @return The color appropriate for the BUYThemeStyle
*/
- (UIColor*)productTitleColor;
/**
* The color for the product "compare at" text
*
* @return The color appropriate for the BUYThemeStyle
* @return The color appropriate for the ThemeStyle
*/
+ (UIColor*)comparePriceTextColor;
/**
* The color for the product's description text
*
* @return The color appropriate for the BUYThemeStyle
* @return The color appropriate for the ThemeStyle
*/
+ (UIColor*)descriptionTextColor;
/**
* The color for the variant option name text
*
* @return The color appropriate for the BUYThemeStyle
*/
- (UIColor*)variantOptionNameTextColor;
/**
* The color for the variant price text
*
* @return The color appropriate for the BUYThemeStyle
* @return The color appropriate for the ThemeStyle
*/
+ (UIColor*)variantPriceTextColor;
/**
* The color for the variant "sold out" text
*
* @return The color appropriate for the BUYThemeStyle
* @return The color appropriate for the ThemeStyle
*/
+ (UIColor*)variantSoldOutTextColor;
/**
* The background color for the variant selection bread crumb view
*
* @return The color appropriate for the BUYThemeStyle
*/
- (UIColor*)variantBreadcrumbsBackground;
/**
* The text color for the variant selection bread crumb view
*
* @return The color appropriate for the BUYThemeStyle
*/
+ (UIColor*)variantBreadcrumbsTextColor;
#pragma mark - Padding and Sizes
/**
......@@ -258,34 +170,4 @@ extern CGFloat const kBuyBottomGradientHeightWithoutPageControl;
*/
+ (UIFont*)errorLabelFont;
#pragma mark - Misc
/**
* Blur effect style for for the product view
*
* @return The blur effect appropriate for the theme
*/
- (UIBlurEffect*)blurEffect;
/**
* Activity indicator style for the product view when loading a product
*
* @return The activity indicator style appropriate for the theme
*/
- (UIActivityIndicatorViewStyle)activityIndicatorViewStyle;
/**
* Navigation bar style for the product view
*
* @return The navigation bar style appropriate for the theme
*/
- (UIBarStyle)navigationBarStyle;
/**
* Apple Pay button style for the product view
*
* @return The button style appropriate for the theme
*/
- (BUYPaymentButtonStyle)paymentButtonStyle;
@end
//
// BUYTheme+Additions.m
// Theme+Additions.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,63 +24,19 @@
// THE SOFTWARE.
//
#import "BUYTheme+Additions.h"
#import "UIFont+BUYAdditions.h"
#import "Theme+Additions.h"
#import "UIFont+Additions.h"
#import "UIColor+Additions.h"
@implementation BUYTheme (Additions)
@implementation Theme (Additions)
#pragma mark - Colors
- (UIColor*)backgroundColor
{
return self.style == BUYThemeStyleDark ? BUY_RGB(26, 26, 26) : [UIColor whiteColor];
}
- (UIColor*)selectedBackgroundColor
{
return self.style == BUYThemeStyleDark ? BUY_RGB(60, 60, 60) : BUY_RGB(242, 242, 242);
}
- (UIColor*)separatorColor
{
return self.style == BUYThemeStyleDark ? BUY_RGB(76, 76, 76) : BUY_RGB(217, 217, 217);
}
- (UIColor*)disclosureIndicatorColor
{
return self.style == BUYThemeStyleDark ? BUY_RGB(76, 76, 76) : BUY_RGB(191, 191, 191);
}
- (UIColor*)checkoutButtonTextColor
{
return self.style == BUYThemeStyleLight ? [UIColor whiteColor] : [UIColor blackColor];
}
+ (UIColor*)topGradientViewTopColor
{
return [UIColor colorWithWhite:0 alpha:0.25f];
}
- (UIColor*)errorTintOverlayColor
{
return self.style == BUYThemeStyleDark ? BUY_RGBA(255, 66, 66, 0.75f) : BUY_RGBA(209, 44, 44, 0.75f);
}
- (UIColor*)navigationBarTitleColor
{
return self.style == BUYThemeStyleDark ? [UIColor whiteColor] : [UIColor blackColor];
}
- (UIColor*)navigationBarTitleVariantSelectionColor
{
return self.style == BUYThemeStyleDark ? BUY_RGB(229, 229, 229) : [UIColor blackColor];
}
- (UIColor*)productTitleColor
{
return self.style == BUYThemeStyleDark ? [UIColor whiteColor] : [UIColor blackColor];
}
+ (UIColor*)comparePriceTextColor
{
return [UIColor colorWithWhite:0.4f alpha:1];
......@@ -91,11 +47,6 @@
return [UIColor colorWithWhite:0.4f alpha:1];
}
- (UIColor*)variantOptionNameTextColor
{
return self.style == BUYThemeStyleDark ? BUY_RGB(76, 76, 76) : BUY_RGB(191, 191, 191);
}
+ (UIColor*)variantPriceTextColor
{
return BUY_RGB(140, 140, 140);
......@@ -106,16 +57,6 @@
return BUY_RGB(220, 96, 96);
}
- (UIColor*)variantBreadcrumbsBackground
{
return self.style == BUYThemeStyleDark ? BUY_RGB(13, 13, 13) : BUY_RGB(229, 229, 229);
}
+ (UIColor*)variantBreadcrumbsTextColor
{
return BUY_RGB(140, 140, 140);
}
#pragma mark - Padding and Sizes
CGFloat const kBuyPaddingSmall = 8.0f;
......@@ -180,26 +121,4 @@ CGFloat const kBuyBottomGradientHeightWithoutPageControl = 20.0f;
return [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
}
#pragma mark - Misc
- (UIBlurEffect*)blurEffect
{
return [UIBlurEffect effectWithStyle:self.style == BUYThemeStyleDark ? UIBlurEffectStyleDark : UIBlurEffectStyleLight];
}
- (UIActivityIndicatorViewStyle)activityIndicatorViewStyle
{
return self.style == BUYThemeStyleDark ? UIActivityIndicatorViewStyleWhite : UIActivityIndicatorViewStyleGray;
}
- (UIBarStyle)navigationBarStyle
{
return self.style == BUYThemeStyleDark ? UIBarStyleBlack : UIBarStyleDefault;
}
- (BUYPaymentButtonStyle)paymentButtonStyle
{
return self.style == BUYThemeStyleLight ? BUYPaymentButtonStyleBlack : BUYPaymentButtonStyleWhite;
}
@end
//
// BUYTheme.h
// Theme.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -29,49 +29,38 @@
/**
* The theme style for the BUYProductViewController
*/
typedef NS_ENUM(NSInteger, BUYThemeStyle){
typedef NS_ENUM(NSInteger, ThemeStyle) {
/**
* Light theme style, providing light backgrounds and light styled UIVisualEffectViews
*/
BUYThemeStyleLight,
ThemeStyleLight,
/**
* Dark theme style, providing dark backgrounds and dark styled UIVisualEffectViews
*/
BUYThemeStyleDark
ThemeStyleDark
};
/**
* This class provides properties used for theming the BUYProductViewController UI elements.
*/
@interface BUYTheme : NSObject
@interface Theme : NSObject
/**
* Used for the highlight color
* Used for the highlight color. Default is the tintColor of the app's keyWindow if not nil,
* other falls back to a "Shopify green" color
*/
@property (nonatomic, strong) UIColor *tintColor;
/**
* Theme style for the views
*/
@property (nonatomic, assign) BUYThemeStyle style;
@property (nonatomic, assign) ThemeStyle style;
/**
* Determines whether a blurred scaled-up product image should appear behind the product details. Default is YES
*/
@property (nonatomic, assign) BOOL showsProductImageBackground;
@end
/**
* Protocol to enable theming for any class
*/
@protocol BUYThemeable <NSObject>
/**
* Sets the theme for the view, and its subviews
*
* @param theme The new theme to apply
*/
- (void)setTheme:(BUYTheme *)theme;
- (void)styleProductViewController;
@end
//
// Theme.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 "DisclosureIndicatorView.h"
#import "ErrorView.h"
#import "NavigationController.h"
#import "OptionSelectionNavigationController.h"
#import "OptionValueCell.h"
#import "ProductDescriptionCell.h"
#import "ProductHeaderCell.h"
#import "ProductVariantCell.h"
#import "OptionBreadCrumbsView.h"
#import "HeaderOverlayView.h"
#import "ProductViewNavigationController.h"
#import "ProductViewController.h"
#import "ProductView.h"
#import "Theme.h"
#import "Theme+Additions.h"
#import "VariantOptionView.h"
#import "VisualEffectView.h"
#import "UIColor+Additions.h"
#import "CheckoutButton.h"
@implementation Theme
- (instancetype)init
{
self = [super init];
if (self) {
self.style = ThemeStyleLight;
self.showsProductImageBackground = YES;
}
return self;
}
- (void)styleProductViewController
{
UIColor *contentBackgroundColor = self.style == ThemeStyleDark ? BUY_RGB(26, 26, 26) : [UIColor whiteColor];
UIColor *contentBackgroundSelectedColor = self.style == ThemeStyleDark ? BUY_RGB(60, 60, 60) : BUY_RGB(242, 242, 242);
UIColor *contentBackgroundComplimentaryColor = self.style == ThemeStyleDark ? [UIColor whiteColor] : [UIColor blackColor];
UIColor *primaryColor = self.tintColor;
UIColor *secondaryLightColor = self.style == ThemeStyleDark ? BUY_RGB(13, 13, 13) : BUY_RGB(229, 229, 229);
UIColor *secondaryMediumColor = self.style == ThemeStyleDark ? BUY_RGB(76, 76, 76) : BUY_RGB(217, 217, 217);
UIColor *secondaryDarkColor = self.style == ThemeStyleDark ? BUY_RGB(76, 76, 76) : BUY_RGB(191, 191, 191);
UIBarStyle barStyle = self.style == ThemeStyleDark ? UIBarStyleBlack : UIBarStyleDefault;
UIColor *errorColor = self.style == ThemeStyleDark ? BUY_RGBA(255, 66, 66, 0.75f) : BUY_RGBA(209, 44, 44, 0.75f);
UIBlurEffectStyle blurEffectStyle = self.style == ThemeStyleDark ? UIBlurEffectStyleDark : UIBlurEffectStyleLight;
UIScrollViewIndicatorStyle scrollViewIndicatorStyle = self.style == ThemeStyleDark ? UIScrollViewIndicatorStyleWhite : UIScrollViewIndicatorStyleDefault;
// Add some Theme-specific styling:
UIColor *navigationBarTitleColor = self.style == ThemeStyleDark ? [UIColor whiteColor] : [UIColor blackColor];
UIColor *navigationBarTitleVariantSelectionColor = self.style == ThemeStyleDark ? BUY_RGB(229, 229, 229) : [UIColor blackColor];
if ([[UINavigationBar class] respondsToSelector:@selector(appearanceWhenContainedInInstancesOfClasses:)]) {
[[UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[[OptionSelectionNavigationController class]]] setTitleTextAttributes:@{ NSForegroundColorAttributeName : navigationBarTitleVariantSelectionColor }];
[[UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[[NavigationController class]]] setTitleTextAttributes:@{ NSForegroundColorAttributeName : navigationBarTitleColor }];
[[UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[[NavigationController class]]] setTintColor:primaryColor];
[[UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[[NavigationController class]]] setBarStyle:barStyle];
[[UITableView appearanceWhenContainedInInstancesOfClasses:@[[NavigationController class]]] setBackgroundColor:contentBackgroundColor];
[[UITableView appearanceWhenContainedInInstancesOfClasses:@[[NavigationController class]]] setSeparatorColor:secondaryMediumColor];
[[UIScrollView appearanceWhenContainedInInstancesOfClasses:@[[NavigationController class]]] setIndicatorStyle:scrollViewIndicatorStyle];
[[UIActivityIndicatorView appearanceWhenContainedInInstancesOfClasses:@[[ProductViewController class]]] setColor:primaryColor];
} else {
[[UINavigationBar appearanceWhenContainedIn:[OptionSelectionNavigationController class], nil] setTitleTextAttributes:@{ NSForegroundColorAttributeName : navigationBarTitleVariantSelectionColor }];
[[UINavigationBar appearanceWhenContainedIn:[NavigationController class], nil] setTitleTextAttributes:@{ NSForegroundColorAttributeName : navigationBarTitleColor }];
[[UINavigationBar appearanceWhenContainedIn:[NavigationController class], nil] setTintColor:primaryColor];
[[UINavigationBar appearanceWhenContainedIn:[NavigationController class], nil] setBarStyle:barStyle];
[[UITableView appearanceWhenContainedIn:[NavigationController class], nil] setBackgroundColor:contentBackgroundColor];
[[UITableView appearanceWhenContainedIn:[NavigationController class], nil] setSeparatorColor:secondaryMediumColor];
[[UIScrollView appearanceWhenContainedIn:[NavigationController class], nil] setIndicatorStyle:scrollViewIndicatorStyle];
[[UIActivityIndicatorView appearanceWhenContainedIn:[ProductViewController class], nil] setColor:primaryColor];
}
[[ProductView appearance] setTintColor:primaryColor];
[[ProductView appearance] setShowsProductImageBackground:self.showsProductImageBackground];
[[VariantOptionView appearance] setOptionNameTextColor:self.style == ThemeStyleDark ? BUY_RGB(76, 76, 76) : BUY_RGB(191, 191, 191)];
[[VisualEffectView appearance] setBlurEffectStyle:blurEffectStyle];
[[CheckoutButton appearance] setBackgroundColor:primaryColor];
[[CheckoutButton appearance] setTextColor:contentBackgroundColor];
[[DisclosureIndicatorView appearance] setTintColor:secondaryDarkColor];
[[ErrorView appearance] setOverlayColor:errorColor];
[[ProductView appearance] setBackgroundColor:contentBackgroundColor];
[[ProductHeaderCell appearance] setProductTitleColor:contentBackgroundComplimentaryColor];
[[ProductHeaderCell appearance] setBackgroundColor:contentBackgroundColor];
[[ProductDescriptionCell appearance] setBackgroundColor:contentBackgroundColor];
[[ProductVariantCell appearance] setBackgroundColor:contentBackgroundColor];
[[ProductVariantCell appearance] setSelectedBackgroundViewBackgroundColor:contentBackgroundSelectedColor];
[[VariantOptionView appearance] setBackgroundColor:contentBackgroundColor];
[[OptionValueCell appearance] setTintColor:primaryColor];
[[OptionValueCell appearance] setBackgroundColor:contentBackgroundColor];
[[OptionValueCell appearance] setSelectedBackgroundViewBackgroundColor:contentBackgroundSelectedColor];
[[HeaderOverlayView appearance] setOverlayBackgroundColor:contentBackgroundColor];
[[OptionBreadCrumbsView appearance] setBackgroundColor:secondaryLightColor];
[[OptionBreadCrumbsView appearance] setVariantOptionTextColor:BUY_RGB(140, 140, 140)];
}
@end
//
// BUYOption.h
// VisualEffectView.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,27 +24,10 @@
// THE SOFTWARE.
//
#import "BUYObject.h"
@import UIKit;
/**
* This represent a BUYOption on a BUYProduct
*/
@interface BUYOption : BUYObject
@interface VisualEffectView : UIVisualEffectView
/**
* Custom product property names like "Size", "Color", and "Material".
* 255 characters limit each.
*/
@property (nonatomic, readonly, copy) NSString *name;
/**
* The order in which the option should optionally appear
*/
@property (nonatomic, readonly, strong) NSNumber *position;
/**
* The associated product ID for this option
*/
@property (nonatomic, readonly, copy) NSNumber *productId;
- (void)setBlurEffectStyle:(UIBlurEffectStyle)blurEffectStyle UI_APPEARANCE_SELECTOR;
@end
//
// NSDictionary+Additions.m
//
// VisualEffectView.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,13 +24,13 @@
// THE SOFTWARE.
//
#import "NSDictionary+Additions.h"
#import "VisualEffectView.h"
@implementation NSDictionary (Additions)
@implementation VisualEffectView
- (id)buy_objectForKey:(NSString *)key
- (void)setBlurEffectStyle:(UIBlurEffectStyle)blurEffectStyle
{
return ([self[key] isKindOfClass:[NSNull class]]) ? nil : self[key];
self.effect = [UIBlurEffect effectWithStyle:blurEffectStyle];
}
@end
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="8191" systemVersion="15A282b" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="rS3-R9-Ivy">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9059" systemVersion="15B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="rS3-R9-Ivy">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9049"/>
</dependencies>
<scenes>
<!--Master-->
......@@ -29,7 +29,7 @@
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<animations/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="calibratedRGB"/>
<sections/>
<connections>
<outlet property="dataSource" destination="pGg-6v-bdr" id="P41-gY-KXY"/>
......
......@@ -25,8 +25,9 @@
//
@import UIKit;
@class BUYCheckout;
@class BUYClient;
@import Buy;
@import PassKit;
@import SafariServices;
extern NSString * const CheckoutCallbackNotification;
......
......@@ -24,24 +24,22 @@
// THE SOFTWARE.
//
@import Buy;
#import "CheckoutViewController.h"
#import "GetCompletionStatusOperation.h"
#import "SummaryItemsTableViewCell.h"
#import "ProductListViewController.h"
@import Buy;
@import PassKit;
@import SafariServices;
#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
......@@ -87,7 +85,7 @@ NSString * const CheckoutCallbackNotification = @"CheckoutCallbackNotification";
[webCheckoutButton addTarget:self action:@selector(checkoutOnWeb) forControlEvents:UIControlEventTouchUpInside];
[footerView addSubview:webCheckoutButton];
UIButton *applePayButton = [BUYPaymentButton buttonWithType:BUYPaymentButtonTypeBuy style:BUYPaymentButtonStyleBlack];
UIButton *applePayButton = [UIButton paymentButtonWithType:PaymentButtonTypeBuy style:PaymentButtonStyleBlack];
applePayButton.translatesAutoresizingMaskIntoConstraints = NO;
[applePayButton addTarget:self action:@selector(checkoutWithApplePay) forControlEvents:UIControlEventTouchUpInside];
[footerView addSubview:applePayButton];
......@@ -139,24 +137,17 @@ NSString * const CheckoutCallbackNotification = @"CheckoutCallbackNotification";
return cell;
}
- (void)addCreditCardToCheckout:(void (^)(BOOL success))callback
- (void)addCreditCardToCheckout:(void (^)(BOOL success, id<BUYPaymentToken> token))callback
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
[self.client storeCreditCard:[self creditCard] checkout:self.checkout completion:^(BUYCheckout *checkout, NSString *paymentSessionId, 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);
callback(error == nil && token, token);
}];
}
......@@ -205,32 +196,23 @@ NSString * const CheckoutCallbackNotification = @"CheckoutCallbackNotification";
}];
}
#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) {
[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 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];
......@@ -241,22 +223,6 @@ NSString * const CheckoutCallbackNotification = @"CheckoutCallbackNotification";
}];
}
- (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
......@@ -265,7 +231,7 @@ NSString * const CheckoutCallbackNotification = @"CheckoutCallbackNotification";
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;
/**
......@@ -292,7 +258,7 @@ NSString * const CheckoutCallbackNotification = @"CheckoutCallbackNotification";
{
PKPaymentRequest *paymentRequest = [[PKPaymentRequest alloc] init];
[paymentRequest setMerchantIdentifier:MERCHANT_ID];
[paymentRequest setMerchantIdentifier:MerchantId];
[paymentRequest setRequiredBillingAddressFields:PKAddressFieldAll];
[paymentRequest setRequiredShippingAddressFields:self.checkout.requiresShipping ? PKAddressFieldAll : PKAddressFieldEmail|PKAddressFieldPhone];
[paymentRequest setSupportedNetworks:@[PKPaymentNetworkVisa, PKPaymentNetworkMasterCard]];
......@@ -406,7 +372,7 @@ NSString * const CheckoutCallbackNotification = @"CheckoutCallbackNotification";
[[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];
......
......@@ -31,7 +31,7 @@
#warning - Enter your shop domain and API Key
#define SHOP_DOMAIN @""
#define API_KEY @""
#define CHANNEL_ID @""
#define APP_ID @""
@interface CollectionListViewController ()
......@@ -51,10 +51,10 @@
self.client = [[BUYClient alloc] initWithShopDomain:SHOP_DOMAIN
apiKey:API_KEY
channelId:CHANNEL_ID];
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) {
......
//
// BUYImageKit.h
// ImageKit.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -30,7 +30,7 @@
/**
* Image generator for a variety of images using the BUYProductViewController.
*/
@interface BUYImageKit : NSObject
@interface ImageKit : NSObject
/**
* Generates a close button image for the variant selection navigation bar.
......
//
// BUYImageKit.m
// ImageKit.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,9 +24,9 @@
// THE SOFTWARE.
//
#import "BUYImageKit.h"
#import "ImageKit.h"
@implementation BUYImageKit
@implementation ImageKit
#pragma mark Drawing Methods
......@@ -164,7 +164,7 @@
+ (UIImage*)imageOfVariantCloseImageWithFrame: (CGRect)frame
{
UIGraphicsBeginImageContextWithOptions(frame.size, NO, 0.0f);
[BUYImageKit drawVariantCloseImageWithFrame: frame];
[ImageKit drawVariantCloseImageWithFrame: frame];
UIImage* imageOfVariantCloseImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
......@@ -175,7 +175,7 @@
+ (UIImage*)imageOfPreviousSelectionIndicatorImageWithFrame: (CGRect)frame
{
UIGraphicsBeginImageContextWithOptions(frame.size, NO, 0.0f);
[BUYImageKit drawPreviousSelectionIndicatorImageWithFrame: frame];
[ImageKit drawPreviousSelectionIndicatorImageWithFrame: frame];
UIImage* imageOfPreviousSelectionIndicatorImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
......@@ -186,7 +186,7 @@
+ (UIImage*)imageOfDisclosureIndicatorImageWithFrame: (CGRect)frame color:(UIColor*)color;
{
UIGraphicsBeginImageContextWithOptions(frame.size, NO, 0.0f);
[BUYImageKit drawDisclosureIndicatorImageWithFrame: frame color:color];
[ImageKit drawDisclosureIndicatorImageWithFrame: frame color:color];
UIImage* imageOfDisclosureIndicatorImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
......@@ -197,7 +197,7 @@
+ (UIImage*)imageOfProductViewCloseImageWithFrame: (CGRect)frame color:(UIColor*)color hasShadow:(BOOL)hasShadow;
{
UIGraphicsBeginImageContextWithOptions(frame.size, NO, 0.0f);
[BUYImageKit drawProductViewCloseImageWithFrame: frame color:color hasShadow:hasShadow];
[ImageKit drawProductViewCloseImageWithFrame: frame color:color hasShadow:hasShadow];
UIImage* imageOfProductViewCloseImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
......@@ -208,7 +208,7 @@
+ (UIImage*)imageOfVariantBackImageWithFrame: (CGRect)frame
{
UIGraphicsBeginImageContextWithOptions(frame.size, NO, 0.0f);
[BUYImageKit drawVariantBackImageWithFrame: frame];
[ImageKit drawVariantBackImageWithFrame: frame];
UIImage* imageOfVariantBackImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
......
//
// PaymentButton.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.
//
typedef NS_ENUM(NSInteger, PaymentButtonStyle) {
PaymentButtonStyleWhite = 0,
PaymentButtonStyleWhiteOutline,
PaymentButtonStyleBlack
};
typedef NS_ENUM(NSInteger, PaymentButtonType) {
PaymentButtonTypePlain = 0,
PaymentButtonTypeBuy,
PaymentButtonTypeSetup NS_ENUM_AVAILABLE_IOS(9_0)
};
@interface PaymentButton : UIButton
+ (instancetype)buttonWithType:(PaymentButtonType)buttonType style:(PaymentButtonStyle)buttonStyle;
@end
//
// BUYPaymentButton.m
// PaymentButton.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,25 +25,25 @@
//
@import PassKit;
#import "BUYPaymentButton.h"
#import "PaymentButton.h"
@interface BUYCustomPaymentButton : UIButton
@interface CustomPaymentButton : UIButton
@property (nonatomic, assign) BUYPaymentButtonType customButtonType;
@property (nonatomic, assign) BUYPaymentButtonStyle customButtonStyle;
@property (nonatomic, assign) PaymentButtonType customButtonType;
@property (nonatomic, assign) PaymentButtonStyle customButtonStyle;
- (void)buttonWithType:(BUYPaymentButtonType)customButtonType style:(BUYPaymentButtonStyle)customButtonStyle;
- (void)buttonWithType:(PaymentButtonType)customButtonType style:(PaymentButtonStyle)customButtonStyle;
@end
@implementation BUYCustomPaymentButton
@implementation CustomPaymentButton
- (void)buttonWithType:(BUYPaymentButtonType)customButtonType style:(BUYPaymentButtonStyle)customButtonStyle {
- (void)buttonWithType:(PaymentButtonType)customButtonType style:(PaymentButtonStyle)customButtonStyle {
self.customButtonType = customButtonType;
self.customButtonStyle = customButtonStyle;
self.layer.cornerRadius = 6;
self.clipsToBounds = YES;
if (self.customButtonStyle == BUYPaymentButtonStyleWhiteOutline) {
if (self.customButtonStyle == PaymentButtonStyleWhiteOutline) {
self.layer.borderColor = [[UIColor blackColor] CGColor];
self.layer.borderWidth = 1;
}
......@@ -62,7 +62,7 @@
UIColor *backgroundColor = [UIColor whiteColor];
UIColor *foregroundColor = [UIColor blackColor];
if (self.customButtonStyle == BUYPaymentButtonStyleBlack) {
if (self.customButtonStyle == PaymentButtonStyleBlack) {
backgroundColor = [UIColor blackColor];
foregroundColor = [UIColor whiteColor];
}
......@@ -78,7 +78,7 @@
[foregroundColor setFill];
switch (self.customButtonType) {
case BUYPaymentButtonTypeBuy: {
case PaymentButtonTypeBuy: {
//// Subframes
CGRect buyWithApplyPay = CGRectMake(CGRectGetMinX(frame) + (CGRectGetWidth(frame) * 0.09790f + 0.5f), CGRectGetMinY(frame) + (CGRectGetHeight(frame) * 0.25000f - 0.32f) + 0.82f, (CGRectGetWidth(frame) * 0.89055f + 0.15f) - (CGRectGetWidth(frame) * 0.09790f + 0.5f) + 0.35f, (CGRectGetHeight(frame) * 0.75414f + 0.5f) - (CGRectGetHeight(frame) * 0.25000f - 0.32f) - 0.82f);
......@@ -413,7 +413,7 @@
}
}
break;
case BUYPaymentButtonTypePlain: {
case PaymentButtonTypePlain: {
//// applePay Drawing
UIBezierPath* applePayPath = UIBezierPath.bezierPath;
[applePayPath moveToPoint: CGPointMake(CGRectGetMinX(frame) + 0.65968f * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.37344f * CGRectGetHeight(frame))];
......@@ -569,17 +569,17 @@
@end
@implementation BUYPaymentButton
@implementation PaymentButton
+ (instancetype)buttonWithType:(BUYPaymentButtonType)buttonType style:(BUYPaymentButtonStyle)buttonStyle {
+ (instancetype)buttonWithType:(PaymentButtonType)buttonType style:(PaymentButtonStyle)buttonStyle {
Class ApplePayButton = NSClassFromString(@"PKPaymentButton");
if (ApplePayButton) {
return (BUYPaymentButton*)[ApplePayButton buttonWithType:buttonType
return (PaymentButton*)[ApplePayButton buttonWithType:buttonType
style:buttonStyle];
} else {
BUYCustomPaymentButton *customPaymentButton = [BUYCustomPaymentButton buttonWithType:UIButtonTypeCustom];
CustomPaymentButton *customPaymentButton = [CustomPaymentButton buttonWithType:UIButtonTypeCustom];
[customPaymentButton buttonWithType:buttonType style:buttonStyle];
return (BUYPaymentButton*)customPaymentButton;
return (PaymentButton*)customPaymentButton;
}
}
......
//
// UIButton+PaymentButton.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;
typedef NS_ENUM(NSInteger, PaymentButtonStyle) {
PaymentButtonStyleWhite = 0,
PaymentButtonStyleWhiteOutline,
PaymentButtonStyleBlack
};
typedef NS_ENUM(NSInteger, PaymentButtonType) {
PaymentButtonTypePlain = 0,
PaymentButtonTypeBuy,
PaymentButtonTypeSetup NS_ENUM_AVAILABLE_IOS(9_0)
};
@interface UIButton (PaymentButton)
+ (UIButton *)paymentButtonWithType:(PaymentButtonType)buttonType style:(PaymentButtonStyle)buttonStyle;
@end
//
// UIButton+PaymentButton.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 PassKit;
#import "CheckoutButton.h"
#import "UIImage+Additions.h"
#import "UIImage+PaymentButton.h"
#import "UIButton+PaymentButton.h"
@implementation UIButton (PaymentButton)
+ (UIButton *)paymentButtonWithType:(PaymentButtonType)buttonType style:(PaymentButtonStyle)buttonStyle
{
if ([PKPaymentButton class]) {
return [PKPaymentButton buttonWithType:(PKPaymentButtonType)buttonType style:(PKPaymentButtonStyle)buttonStyle];
}
UIButton *button = [CheckoutButton new];
UIColor *fillColor;
UIColor *strokeColor;
switch (buttonStyle) {
case PaymentButtonStyleBlack:
fillColor = [UIColor blackColor];
break;
case PaymentButtonStyleWhite:
fillColor = [UIColor whiteColor];
break;
case PaymentButtonStyleWhiteOutline:
fillColor = [UIColor whiteColor];
strokeColor = [UIColor blackColor];
break;
}
UIImage *backgroundImage = [[UIImage templateImageWithFill:fillColor stroke:strokeColor edgeInsets:UIEdgeInsetsMake(4.0f, 4.0f, 4.0f, 4.0f)] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
[button setBackgroundImage:backgroundImage forState:UIControlStateNormal];
UIImage *image = [UIImage paymentButtonImageWithFrame:CGRectMake(0, 0, 120.0f, 44.0f) style:buttonStyle type:buttonType];
[button setImage:image forState:UIControlStateNormal];
return button;
}
@end
//
// Buy.h
// UIImage+PaymentButton.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -23,38 +23,9 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import <UIKit/UIKit.h>
#import "UIButton+PaymentButton.h"
/**
* Umbrella header used for Cocoapods
*/
#import "BUYApplePayAdditions.h"
#import "BUYApplePayHelpers.h"
#import "BUYAddress.h"
#import "BUYCart.h"
#import "BUYCartLineItem.h"
#import "BUYCheckout.h"
#import "BUYCheckoutAttribute.h"
#import "BUYClient+Test.h"
#import "BUYClient.h"
#import "BUYCollection.h"
#import "BUYCreditCard.h"
#import "BUYDiscount.h"
#import "BUYError.h"
#import "BUYGiftCard.h"
#import "BUYImage.h"
#import "BUYLineItem.h"
#import "BUYMaskedCreditCard.h"
#import "BUYOption.h"
#import "BUYOptionValue.h"
#import "BUYOrder.h"
#import "BUYPaymentButton.h"
#import "BUYProduct.h"
#import "BUYProductVariant.h"
#import "BUYProductViewController.h"
#import "BUYShippingRate.h"
#import "BUYShop.h"
#import "BUYStoreViewController.h"
#import "BUYTaxLine.h"
#import "BUYTheme.h"
#import "BUYViewController.h"
@interface UIImage (PaymentButton)
+ (UIImage *)paymentButtonImageWithFrame:(CGRect)originalFrame style:(PaymentButtonStyle)style type:(PaymentButtonType)type;
@end
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -53,7 +53,7 @@ typedef NS_ENUM(NSInteger, UITableViewDiscountGiftCardSection) {
@implementation PreCheckoutViewController
- (instancetype)initWithClient:(BUYClient *)client checkout:(BUYCheckout *)checkout;
- (instancetype)initWithClient:(BUYClient *)client checkout:(BUYCheckout *)checkout
{
NSParameterAssert(client);
NSParameterAssert(checkout);
......@@ -68,7 +68,8 @@ typedef NS_ENUM(NSInteger, UITableViewDiscountGiftCardSection) {
return self;
}
- (void)viewDidLoad {
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = @"Add Discount or Gift Card(s)";
......@@ -192,7 +193,7 @@ typedef NS_ENUM(NSInteger, UITableViewDiscountGiftCardSection) {
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
BUYDiscount *discount = [[BUYDiscount alloc] initWithCode:[alertController.textFields[0] text]];
BUYDiscount *discount = [self.client.modelManager discountWithCode:[alertController.textFields[0] text]];
self.checkout.discount = discount;
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
......@@ -236,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];
......
//
// ActionableFooterView.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 "CheckoutButton.h"
#import "UIButton+PaymentButton.h"
@interface ActionableFooterView : UIView
- (void)setApplePayAvailable:(BOOL)applePayAvailable requiresSetup:(BOOL)requiresSetup;
@property (nonatomic, readonly) CheckoutButton *actionButton;
/**
* On iOS 8.3+ this will be a PKPaymentButton
*/
@property (nonatomic, readonly) UIButton *paymentButton;
@property (nonatomic) BOOL buttonsEnabled;
/**
* A view which sits above the buttons.
* Can be used to add a description or other content to the footer.
*/
@property (nonatomic, readonly) UIView *extensionView;
@property (nonatomic) PaymentButtonStyle paymentButtonStyle UI_APPEARANCE_SELECTOR;
@property (nonatomic) UIColor *separatorColor UI_APPEARANCE_SELECTOR;
@end
//
// ActionableFooterView.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 "ActionableFooterView.h"
@interface ActionableFooterView()
@property (nonatomic) BOOL applePayAvailable;
@property (nonatomic) BOOL applePayRequiresSetup;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *applePayLeadingConstraint;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *firstButtonTrailingConstraint;
@property (strong, nonatomic) IBOutlet CheckoutButton *actionButton;
@property (strong, nonatomic) IBOutlet UIView *paymentButtonContainer;
@property (strong, nonatomic) IBOutlet UIView *extensionView;
@property (strong, nonatomic) UIButton *paymentButton;
@end
@implementation ActionableFooterView
- (instancetype)init
{
return [[NSBundle bundleForClass:self.class] loadNibNamed:NSStringFromClass([self class]) owner:nil options:nil].firstObject;
}
- (void)awakeFromNib
{
[super awakeFromNib];
self.actionButton.backgroundColor = nil;
[self.actionButton setTitle:nil forState:UIControlStateNormal];
self.paymentButtonStyle = PaymentButtonStyleBlack;
self.paymentButtonContainer.backgroundColor = nil;
}
- (void)setApplePayAvailable:(BOOL)applePayAvailable requiresSetup:(BOOL)requiresSetup
{
_applePayAvailable = applePayAvailable;
_applePayRequiresSetup = requiresSetup;
self.paymentButtonContainer.hidden = !applePayAvailable;
PaymentButtonType type = self.applePayRequiresSetup ? PaymentButtonTypeSetup : PaymentButtonTypeBuy;
if (!self.paymentButton) {
_paymentButton = [UIButton paymentButtonWithType:type style:self.paymentButtonStyle];
[self.paymentButtonContainer addSubview:self.paymentButton];
self.paymentButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.paymentButtonContainer addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_paymentButton]|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(_paymentButton)]];
[self.paymentButtonContainer addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_paymentButton]|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(_paymentButton)]];
}
[self setNeedsUpdateConstraints];
}
- (void)setLayoutMargins:(UIEdgeInsets)layoutMargins
{
[super setLayoutMargins:layoutMargins];
self.applePayLeadingConstraint.constant = self.layoutMargins.left;
}
- (void)layoutSubviews
{
[super layoutSubviews];
[self setNeedsUpdateConstraints];
}
- (void)setButtonsEnabled:(BOOL)buttonsEnabled
{
self.actionButton.enabled = buttonsEnabled;
self.paymentButton.enabled = buttonsEnabled;
self.paymentButton.alpha = buttonsEnabled ? 1.0f : 0.5f;
}
- (void)updateConstraints
{
if (self.applePayAvailable) {
CGFloat trailingConstant = (CGRectGetWidth(self.bounds) - self.layoutMargins.right) * 0.5f;
self.firstButtonTrailingConstraint.constant = trailingConstant;
} else {
self.firstButtonTrailingConstraint.constant = 0.0f;
}
[super updateConstraints];
}
- (void)setSeparatorColor:(UIColor *)separatorColor
{
self.layer.shadowColor = separatorColor.CGColor;
self.layer.shadowOffset = CGSizeMake(0, - 1 / [UIScreen mainScreen].scale);
self.layer.shadowRadius = 0.0f;
self.layer.shadowOpacity = 1.0f;
}
@end
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="10116" systemVersion="15E65" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
</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" customClass="ActionableFooterView">
<rect key="frame" x="0.0" y="0.0" width="320" height="100"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<visualEffectView opaque="NO" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2he-LW-1Mz">
<rect key="frame" x="0.0" y="0.0" width="320" height="100"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" id="tOf-FE-2kG">
<rect key="frame" x="0.0" y="0.0" width="320" height="100"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jjm-5z-kCD" userLabel="paymentContainer">
<rect key="frame" x="165" y="46" width="145" height="44"/>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Eoe-n5-0iT" customClass="CheckoutButton">
<rect key="frame" x="10" y="46" width="145" height="44"/>
<color key="backgroundColor" red="0.00059560901718214154" green="0.70855957269668579" blue="0.99971479177474976" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="44" id="Yod-FN-PBJ"/>
</constraints>
<state key="normal" title="Add to Cart">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</state>
</button>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="QbM-Nc-TSH">
<rect key="frame" x="0.0" y="10" width="320" height="36"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
</subviews>
<constraints>
<constraint firstAttribute="trailingMargin" secondItem="Eoe-n5-0iT" secondAttribute="trailing" constant="155" id="4jE-2h-gr6"/>
<constraint firstItem="Eoe-n5-0iT" firstAttribute="leading" secondItem="tOf-FE-2kG" secondAttribute="leadingMargin" id="ACp-Cb-o3A"/>
<constraint firstItem="jjm-5z-kCD" firstAttribute="height" secondItem="Eoe-n5-0iT" secondAttribute="height" id="DoE-w1-naR"/>
<constraint firstItem="QbM-Nc-TSH" firstAttribute="leading" secondItem="tOf-FE-2kG" secondAttribute="leading" id="Q7m-41-SnI"/>
<constraint firstItem="QbM-Nc-TSH" firstAttribute="top" secondItem="tOf-FE-2kG" secondAttribute="topMargin" id="Tbz-Z9-Xyu"/>
<constraint firstItem="jjm-5z-kCD" firstAttribute="leading" secondItem="Eoe-n5-0iT" secondAttribute="trailing" constant="10" id="UrY-kJ-C6C"/>
<constraint firstAttribute="bottomMargin" secondItem="Eoe-n5-0iT" secondAttribute="bottom" id="WHF-0k-ScU"/>
<constraint firstItem="jjm-5z-kCD" firstAttribute="width" secondItem="Eoe-n5-0iT" secondAttribute="width" id="fop-kv-C9D"/>
<constraint firstItem="jjm-5z-kCD" firstAttribute="centerY" secondItem="Eoe-n5-0iT" secondAttribute="centerY" id="g86-Vu-ZpD"/>
<constraint firstItem="Eoe-n5-0iT" firstAttribute="top" secondItem="QbM-Nc-TSH" secondAttribute="bottom" id="pwX-zC-1fR"/>
<constraint firstAttribute="trailing" secondItem="QbM-Nc-TSH" secondAttribute="trailing" id="yYy-IX-gUN"/>
</constraints>
</view>
<blurEffect style="extraLight"/>
</visualEffectView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="2he-LW-1Mz" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="9VD-ID-fkE"/>
<constraint firstItem="2he-LW-1Mz" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="centerY" id="EFC-N3-UwK"/>
<constraint firstItem="2he-LW-1Mz" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="nzn-ri-Fq0"/>
<constraint firstItem="2he-LW-1Mz" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="xUR-8Z-blk"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<edgeInsets key="layoutMargins" top="10" left="10" bottom="10" right="10"/>
<connections>
<outlet property="actionButton" destination="Eoe-n5-0iT" id="slV-do-iC5"/>
<outlet property="applePayLeadingConstraint" destination="UrY-kJ-C6C" id="CBg-TA-i3I"/>
<outlet property="extensionView" destination="QbM-Nc-TSH" id="1rQ-Kd-AvH"/>
<outlet property="firstButtonTrailingConstraint" destination="4jE-2h-gr6" id="kTF-KV-LGT"/>
<outlet property="paymentButtonContainer" destination="jjm-5z-kCD" id="tgu-5h-QO3"/>
</connections>
<point key="canvasLocation" x="142" y="525"/>
</view>
</objects>
</document>
//
// BUYImageView.h
// AsyncImageView.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,14 +25,14 @@
//
@import UIKit;
#import "BUYTheme.h"
@import Buy;
extern float const imageDuration;
/**
* Provides an easy way to asynchronously load images from a URL
*/
@interface BUYImageView : UIImageView <BUYThemeable>
@interface AsyncImageView : UIImageView
@property (nonatomic, assign) BOOL showsActivityIndicator;
......@@ -65,4 +65,13 @@ extern float const imageDuration;
*/
- (BOOL)isPortraitOrSquare;
/**
* Load an image asynchronously from an BUYImageLink and animate the transition. Will use the optimal image size for the ImageView
*
* @param imageLink the BUYImageLink that points to the image asset to use
* @param animateChange YES to animation the image transition
* @param completion Completion block returning the image or an error
*/
- (void)loadImageLink:(BUYImageLink *)imageLink animateChange:(BOOL)animateChange completion:(void (^)(UIImage *image, NSError *error))completion;
@end
//
// BUYImageView.m
// AsyncImageView.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,19 +24,47 @@
// THE SOFTWARE.
//
#import "BUYImageView.h"
#import "BUYTheme+Additions.h"
#import "AsyncImageView.h"
float const imageDuration = 0.1f;
@interface BUYImageView ()
static NSUInteger const memoryCacheSize = 10 * 1024 * 1024; // 10 MB
static NSUInteger const diskCacheSize = 50 * 1024 * 1024; // 50 MB
@interface NSURLSession (BUYImageSession)
+ (instancetype)buy_sharedImageSession;
@end
@implementation NSURLSession (BUYImageSession)
+ (instancetype)buy_sharedImageSession
{
static NSURLSession *_sharedSession = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.URLCache = [[NSURLCache alloc] initWithMemoryCapacity:memoryCacheSize diskCapacity:diskCacheSize diskPath:nil];
_sharedSession = [NSURLSession sessionWithConfiguration:config];
});
return _sharedSession;
}
@end
@interface AsyncImageView ()
@property (nonatomic, strong) NSURLSessionDataTask *task;
@property (nonatomic, strong) UIActivityIndicatorView *activityIndicatorView;
@end
@implementation BUYImageView
@implementation AsyncImageView
- (instancetype)init
{
......@@ -104,7 +132,7 @@ float const imageDuration = 0.1f;
if (self.showsActivityIndicator) {
[self.activityIndicatorView startAnimating];
}
self.task = [[NSURLSession sharedSession] dataTaskWithURL:imageURL completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
self.task = [[NSURLSession buy_sharedImageSession] dataTaskWithURL:imageURL completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
UIImage *image = [UIImage imageWithData:data];
if (setImage) {
......@@ -119,19 +147,23 @@ float const imageDuration = 0.1f;
[self.task resume];
}
- (void)cancelImageTask {
- (void)cancelImageTask
{
[self.task cancel];
self.task = nil;
}
- (void)setTheme:(BUYTheme *)theme
- (BOOL)isPortraitOrSquare
{
self.activityIndicatorView.activityIndicatorViewStyle = [theme activityIndicatorViewStyle];
return self.image.size.height >= self.image.size.width;
}
- (BOOL)isPortraitOrSquare
- (void)loadImageLink:(BUYImageLink *)imageLink animateChange:(BOOL)animateChange completion:(void (^)(UIImage *image, NSError *error))completion;
{
return self.image.size.height >= self.image.size.width;
BUYImageURLSize size = [self buy_imageSize];
NSURL *url = [imageLink imageURLWithSize:size];
[self loadImageWithURL:url animateChange:animateChange completion:completion];
}
@end
//
// BUYCheckoutButton.h
// CheckoutButton.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,12 +25,18 @@
//
@import UIKit;
#import "BUYTheme.h"
/**
* A themed UIButton that includes a UIActivityIndicator
*/
@interface BUYCheckoutButton : UIButton <BUYThemeable>
@interface CheckoutButton : UIButton
/**
* Creates a checkout button with UIButtonTypeSystem which inherits its color from the superview's tintColor
*
* @return A CheckoutButton with UIButtonTypeSystem
*/
+(instancetype)checkoutButton;
/**
* Show a UIActivityIndicator in place of text while loading
......@@ -39,4 +45,11 @@
*/
- (void)showActivityIndicator:(BOOL)show;
/**
* Sets the button text color
*
* @param color The color for the button
*/
- (void)setTextColor:(UIColor*)color UI_APPEARANCE_SELECTOR;
@end
//
// BUYCheckoutButton.m
// CheckoutButton.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,39 +24,61 @@
// THE SOFTWARE.
//
#import "BUYCheckoutButton.h"
#import "BUYTheme+Additions.h"
#import "CheckoutButton.h"
#import "UIColor+Additions.h"
#import "UIImage+Additions.h"
@interface BUYCheckoutButton ()
@interface CheckoutButton ()
@property (nonatomic, weak) BUYTheme *theme;
@property (nonatomic, strong) UIActivityIndicatorView *activityIndicator;
@property (nonatomic, strong) UIColor *textColor;
@end
@implementation BUYCheckoutButton
@implementation CheckoutButton
- (void)setHighlighted:(BOOL)highlighted
+ (instancetype)checkoutButton
{
[super setHighlighted:highlighted];
self.backgroundColor = highlighted ? [self.theme.tintColor colorWithAlphaComponent:0.4f] : self.theme.tintColor;
CheckoutButton *checkoutButton = [super buttonWithType:UIButtonTypeSystem];
[checkoutButton commonInit];
return checkoutButton;
}
- (void)setTheme:(BUYTheme *)theme
- (instancetype)initWithFrame:(CGRect)frame
{
_theme = theme;
self.tintColor = theme.tintColor;
self.backgroundColor = self.tintColor;
UIColor *textColor = [theme checkoutButtonTextColor];
[self setTitleColor:textColor forState:UIControlStateNormal];
self = [super initWithFrame:frame];
if (self) {
[self commonInit];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
[self commonInit];
}
return self;
}
- (void)commonInit
{
[self setBackgroundImage:[UIImage templateButtonBackgroundImage] forState:UIControlStateNormal];
[self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[self setTitleColor:[[UIColor whiteColor] colorWithAlphaComponent:0.5f] forState:UIControlStateDisabled];
}
- (void)setTextColor:(UIColor*)color
{
_textColor = color;
[self setTitleColor:color forState:UIControlStateNormal];
}
- (UIActivityIndicatorView *)activityIndicator
{
if (_activityIndicator == nil) {
UIActivityIndicatorViewStyle style = self.theme.style == BUYThemeStyleLight ? UIActivityIndicatorViewStyleWhite : UIActivityIndicatorViewStyleGray;
_activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:style];
_activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
_activityIndicator.translatesAutoresizingMaskIntoConstraints = NO;
_activityIndicator.hidesWhenStopped = YES;
[self addSubview:_activityIndicator];
......@@ -77,7 +99,7 @@
}
else {
[self.activityIndicator stopAnimating];
[self setTheme:self.theme];
[self setTitleColor:self.textColor forState:UIControlStateNormal];
}
}
......
//
// AppDelegate.h
// DisclosureIndicatorView.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -26,10 +26,6 @@
@import UIKit;
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@interface DisclosureIndicatorView : UIImageView
@end
//
// BUYTheme.m
// DisclosureIndicatorView.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,20 +24,17 @@
// THE SOFTWARE.
//
#import "BUYTheme.h"
#import "DisclosureIndicatorView.h"
#import "ImageKit.h"
@implementation BUYTheme
@implementation DisclosureIndicatorView
- (instancetype)init
{
self = [super init];
if (self) {
self.tintColor = [UIColor colorWithRed:0.48f green:0.71f blue:0.36f alpha:1.0f];
self.style = BUYThemeStyleLight;
self.showsProductImageBackground = YES;
self.image = [[ImageKit imageOfDisclosureIndicatorImageWithFrame:CGRectMake(0, 0, 10, 16) color:[UIColor blackColor]] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
}
return self;
}
......
//
// BUYProductViewErrorView.h
// ErrorView.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,12 +25,11 @@
//
@import UIKit;
@class BUYTheme;
/**
* A customer toast error view to use in the BUYProductView.
* A customer toast error view to use in the ProductView.
*/
@interface BUYProductViewErrorView : UIView
@interface ErrorView : UIView
/**
* The label containing the error message.
......@@ -47,13 +46,8 @@
*/
@property (nonatomic, strong) NSLayoutConstraint *visibleConstraint;
/**
* Initializer that create an error view with a theme.
*
* @param theme The theme for the error view.
*
* @return An error view.
*/
- (instancetype)initWithTheme:(BUYTheme*)theme;
- (void)setOverlayColor:(UIColor*)color UI_APPEARANCE_SELECTOR;
- (void)presentErrorViewWithMessage:(NSString *)errorMessage completion:(void (^)(void))callback;
@end
//
// BUYProductViewErrorView.m
// ErrorView.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,18 +24,24 @@
// THE SOFTWARE.
//
#import "BUYProductViewErrorView.h"
#import "BUYTheme.h"
#import "BUYTheme+Additions.h"
#import "ErrorView.h"
@implementation BUYProductViewErrorView
static CGFloat const kPaddingMedium = 12.0f;
static CGFloat const kPaddingExtraLarge = 16.0f;
- (instancetype)initWithTheme:(BUYTheme*)theme
@interface ErrorView ()
@property (nonatomic, strong) UIView *overlayView;
@end
@implementation ErrorView
- (instancetype)init
{
self = [super init];
if (self) {
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *visualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
UIVisualEffectView *visualEffectView = [[UIVisualEffectView alloc] init];
visualEffectView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:visualEffectView];
......@@ -48,29 +54,28 @@
metrics:nil
views:NSDictionaryOfVariableBindings(visualEffectView)]];
UIView *redTintOverlayView = [[UIView alloc] init];
redTintOverlayView.translatesAutoresizingMaskIntoConstraints = NO;
redTintOverlayView.backgroundColor = [theme errorTintOverlayColor];
[visualEffectView.contentView addSubview:redTintOverlayView];
[visualEffectView.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[redTintOverlayView]|"
_overlayView = [[UIView alloc] init];
_overlayView.translatesAutoresizingMaskIntoConstraints = NO;
[visualEffectView.contentView addSubview:_overlayView];
[visualEffectView.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_overlayView]|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(redTintOverlayView)]];
[visualEffectView.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[redTintOverlayView]|"
views:NSDictionaryOfVariableBindings(_overlayView)]];
[visualEffectView.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_overlayView]|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(redTintOverlayView)]];
views:NSDictionaryOfVariableBindings(_overlayView)]];
_errorLabel = [[UILabel alloc] init];
_errorLabel.translatesAutoresizingMaskIntoConstraints = NO;
_errorLabel.textAlignment = NSTextAlignmentCenter;
_errorLabel.font = [BUYTheme errorLabelFont];
_errorLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
_errorLabel.textColor = [UIColor whiteColor];
_errorLabel.backgroundColor = [UIColor clearColor];
_errorLabel.numberOfLines = 0;
[visualEffectView.contentView addSubview:_errorLabel];
NSDictionary *metricsDictionary = @{ @"paddingExtraLarge" : @(kBuyPaddingExtraLarge), @"paddingMedium" : @(kBuyPaddingMedium) };
NSDictionary *metricsDictionary = @{ @"paddingExtraLarge" : @(kPaddingExtraLarge), @"paddingMedium" : @(kPaddingMedium) };
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(paddingExtraLarge)-[_errorLabel]-(paddingExtraLarge)-|"
options:0
......@@ -84,4 +89,38 @@
return self;
}
- (void)setOverlayColor:(UIColor*)color
{
self.overlayView.backgroundColor = color;
}
- (void)presentErrorViewWithMessage:(NSString *)errorMessage completion:(void (^)(void))callback
{
self.errorLabel.text = errorMessage;
[NSLayoutConstraint deactivateConstraints:@[self.hiddenConstraint]];
[NSLayoutConstraint activateConstraints:@[self.visibleConstraint]];
[UIView animateWithDuration:0.3f
delay:0
usingSpringWithDamping:0.8f
initialSpringVelocity:10
options:0
animations:^{
self.alpha = 1;
[self layoutIfNeeded];
}
completion:^(BOOL finished) {
[NSLayoutConstraint deactivateConstraints:@[self.visibleConstraint]];
[NSLayoutConstraint activateConstraints:@[self.hiddenConstraint]];
[UIView animateWithDuration:0.3f delay:3.0f options:0 animations:^{
self.alpha = 0;
[self layoutIfNeeded];
} completion:^(BOOL finished) {
[self removeFromSuperview];
if (callback) callback();
}];
}];
}
@end
//
// BUYGradientView.h
// GradientView.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -29,7 +29,7 @@
/**
* Easily create a view with a vertical gradient with two colors
*/
@interface BUYGradientView : UIView
@interface GradientView : UIView
/**
* The color of the top part of the gradient
......
//
// BUYGradientView.m
// GradientView.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,9 +24,9 @@
// THE SOFTWARE.
//
#import "BUYGradientView.h"
#import "GradientView.h"
@implementation BUYGradientView
@implementation GradientView
- (instancetype)init
{
......@@ -34,14 +34,16 @@
if (self) {
self.backgroundColor = [UIColor clearColor];
self.topColor = [UIColor colorWithWhite:0 alpha:0.5f];
self.bottomColor = [UIColor clearColor];
self.bottomColor = [UIColor colorWithWhite:0 alpha:0];
}
return self;
}
- (void)drawRect:(CGRect)rect {
- (void)drawRect:(CGRect)rect
{
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = UIGraphicsGetCurrentContext();
NSArray *gradientColors = [NSArray arrayWithObjects:(id)self.topColor.CGColor, (id)self.bottomColor.CGColor, nil];
CGFloat gradientLocations[] = {0, 1};
......
//
// BUYProductViewHeaderBackgroundImageView.h
// HeaderBackgroundView.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,30 +25,20 @@
//
@import UIKit;
@class BUYImageView;
@class BUYTheme;
@class BUYImage;
@class AsyncImageView;
@class BUYImageLink;
/**
* A background for the product view that displays the currently displayed
* product or variant image behind a blurry UIVisualEffectView.
*/
@interface BUYProductViewHeaderBackgroundImageView : UIView
/**
* Initializer that takes a BUYTheme
*
* @param theme The product view theme
*
* @return An instance of BUYProductViewHeaderBackgroundImageView
*/
- (instancetype)initWithTheme:(BUYTheme*)theme;
@interface HeaderBackgroundView : UIView
/**
* Set the product image on the image view
*
* @param image The currently displayed product or variant image
*/
- (void)setBackgroundProductImage:(BUYImage *)image;
- (void)setBackgroundProductImage:(BUYImageLink *)image;
@end
//
// BUYProductViewHeaderBackgroundImageView.m
// HeaderBackgroundView.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,25 +24,23 @@
// THE SOFTWARE.
//
#import "BUYProductViewHeaderBackgroundImageView.h"
#import "BUYTheme.h"
#import "BUYImageView.h"
#import "BUYImage.h"
#import "BUYTheme+Additions.h"
#import "AsyncImageView.h"
#import "HeaderBackgroundView.h"
#import "VisualEffectView.h"
@interface BUYProductViewHeaderBackgroundImageView ()
@interface HeaderBackgroundView ()
@property (nonatomic, strong) BUYImageView *productImageView;
@property (nonatomic, strong) AsyncImageView *productImageView;
@end
@implementation BUYProductViewHeaderBackgroundImageView
@implementation HeaderBackgroundView
- (instancetype)initWithTheme:(BUYTheme*)theme
- (instancetype)init
{
self = [super init];
if (self) {
self.productImageView = [[BUYImageView alloc] init];
self.productImageView = [[AsyncImageView alloc] init];
self.productImageView.clipsToBounds = YES;
self.productImageView.translatesAutoresizingMaskIntoConstraints = NO;
self.productImageView.backgroundColor = [UIColor clearColor];
......@@ -64,7 +62,7 @@
multiplier:1.0
constant:0.0]];
UIVisualEffectView *visualEffectView = [[UIVisualEffectView alloc] initWithEffect:[theme blurEffect]];
VisualEffectView *visualEffectView = [[VisualEffectView alloc] init];
visualEffectView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:visualEffectView];
......@@ -86,10 +84,9 @@
return self;
}
- (void)setBackgroundProductImage:(BUYImage *)image
- (void)setBackgroundProductImage:(BUYImageLink *)image
{
NSString *string = [image.src stringByReplacingOccurrencesOfString:[NSString stringWithFormat:@".%@", [image.src pathExtension]] withString:[NSString stringWithFormat:@"_small.%@", [image.src pathExtension]]];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@", string]];
NSURL *url = [image imageURLWithSize:BUYImageURLSize100x100];
[self.productImageView loadImageWithURL:url animateChange:YES completion:NULL];
}
......
//
// BUYProductViewHeaderOverlay.h
// HeaderOverlayView.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,23 +25,15 @@
//
@import UIKit;
@class BUYTheme;
/**
* An overlay + blur effect when the product view scrolls up
* to hide the image view and create a nice transition into
* the navigation bar.
*/
@interface BUYProductViewHeaderOverlay : UIView
@interface HeaderOverlayView : UIView
/**
* Initializer that takes a BUYTheme
*
* @param theme The product view theme
*
* @return An instance of BUYProductViewHeaderOverlay
*/
- (instancetype)initWithTheme:(BUYTheme*)theme;
@property (nonatomic) UIColor *overlayBackgroundColor UI_APPEARANCE_SELECTOR;
/**
* Used to determine the current visibility of the effect based on content offset and the navigationbar height.
......
//
// BUYProductViewHeaderOverlay.m
// HeaderOverlayView.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,20 +24,19 @@
// THE SOFTWARE.
//
#import "BUYProductViewHeaderOverlay.h"
#import "BUYTheme.h"
#import "BUYTheme+Additions.h"
#import "HeaderOverlayView.h"
#import "VisualEffectView.h"
@interface BUYProductViewHeaderOverlay ()
@interface HeaderOverlayView ()
@property (nonatomic, strong) UIView *overlayView;
@property (nonatomic, strong) UIView *visualEffectContainerView;
@end
@implementation BUYProductViewHeaderOverlay
@implementation HeaderOverlayView
- (instancetype)initWithTheme:(BUYTheme*)theme
- (instancetype)init
{
self = [super init];
if (self) {
......@@ -51,7 +50,7 @@
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_visualEffectContainerView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_visualEffectContainerView)]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_visualEffectContainerView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_visualEffectContainerView)]];
UIVisualEffectView *visualEffectView = [[UIVisualEffectView alloc] initWithEffect:[theme blurEffect]];
VisualEffectView *visualEffectView = [[VisualEffectView alloc] init];
visualEffectView.translatesAutoresizingMaskIntoConstraints = NO;
[_visualEffectContainerView addSubview:visualEffectView];
......@@ -60,7 +59,6 @@
_overlayView = [[UIView alloc] init];
_overlayView.alpha = 0;
_overlayView.backgroundColor = [theme backgroundColor];
_overlayView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_overlayView];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_overlayView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_overlayView)]];
......@@ -69,6 +67,11 @@
return self;
}
-(void)setOverlayBackgroundColor:(UIColor *)overlayBackgroundColor
{
_overlayView.backgroundColor = overlayBackgroundColor;
}
static CGFloat visualEffectViewThreshold = 200.0f;
static CGFloat overlayViewThreshold = 100.0f;
......
//
// BUYProductDescriptionCell.h
// ProductDescriptionCell.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,12 +25,11 @@
//
@import UIKit;
#import "BUYTheme.h"
/**
* Table view cell containing the product description
*/
@interface BUYProductDescriptionCell : UITableViewCell <BUYThemeable>
@interface ProductDescriptionCell : UITableViewCell
/**
* Converts the product description from HTML to an attributed string
......
//
// BUYProductDescriptionCell.m
// ProductDescriptionCell.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,18 +24,16 @@
// THE SOFTWARE.
//
#import "BUYProductDescriptionCell.h"
#import "BUYTheme.h"
#import "BUYTheme+Additions.h"
#import "ProductDescriptionCell.h"
#import "Theme+Additions.h"
@interface BUYProductDescriptionCell ()
@interface ProductDescriptionCell ()
@property (nonatomic, strong) UIColor *textColor;
@property (nonatomic, strong) UILabel *descriptionLabel;
@property (nonatomic, strong) BUYTheme *theme;
@end
@implementation BUYProductDescriptionCell
@implementation ProductDescriptionCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
......@@ -54,7 +52,7 @@
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_descriptionLabel]-|" options:0 metrics:nil views:views]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[_descriptionLabel]-|" options:0 metrics:nil views:views]];
_textColor = [BUYTheme descriptionTextColor];
_textColor = [Theme descriptionTextColor];
}
return self;
......@@ -85,10 +83,9 @@
return self.descriptionLabel.attributedText.string;
}
- (void)setTheme:(BUYTheme *)theme
- (void)setBackgroundColor:(UIColor *)backgroundColor
{
_theme = theme;
self.backgroundColor = [theme backgroundColor];
[super setBackgroundColor:backgroundColor];
self.descriptionLabel.backgroundColor = self.backgroundColor;
}
......
//
// BUYProductHeaderCell.h
// ProductHeaderCell.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,13 +25,12 @@
//
@import UIKit;
#import "BUYTheme.h"
@class BUYProductVariant;
@import Buy;
/**
* Table view cell containing the product title, price and compare-at/sold out text
*/
@interface BUYProductHeaderCell : UITableViewCell <BUYThemeable>
@interface ProductHeaderCell : UITableViewCell
/**
* Sets the title, price and optionally compare-at/sold out texts
......@@ -41,4 +40,6 @@
*/
- (void)setProductVariant:(BUYProductVariant *)productVariant withCurrencyFormatter:(NSNumberFormatter*)currencyFormatter;
- (void)setProductTitleColor:(UIColor*)color UI_APPEARANCE_SELECTOR;
@end
//
// BUYProductHeaderCell.m
// ProductHeaderCell.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,23 +24,20 @@
// THE SOFTWARE.
//
#import "BUYProductHeaderCell.h"
#import "BUYProductVariant.h"
#import "BUYProduct.h"
#import "UIFont+BUYAdditions.h"
#import "BUYTheme+Additions.h"
#import "ProductHeaderCell.h"
#import "UIFont+Additions.h"
#import "Theme+Additions.h"
@interface BUYProductHeaderCell ()
@interface ProductHeaderCell ()
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UILabel *priceLabel;
@property (nonatomic, strong) UILabel *comparePriceLabel;
@property (nonatomic, strong) BUYTheme *theme;
@property (nonatomic, strong) BUYProductVariant *productVariant;
@end
@implementation BUYProductHeaderCell
@implementation ProductHeaderCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
......@@ -52,7 +49,7 @@
_titleLabel = [[UILabel alloc] init];
_titleLabel.textColor = [UIColor blackColor];
_titleLabel.font = [BUYTheme productTitleFont];
_titleLabel.font = [Theme productTitleFont];
_titleLabel.numberOfLines = 0;
_titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:_titleLabel];
......@@ -62,7 +59,7 @@
[self.contentView addSubview:priceView];
_priceLabel = [[UILabel alloc] init];
_priceLabel.font = [BUYTheme productPriceFont];
_priceLabel.font = [Theme productPriceFont];
_priceLabel.translatesAutoresizingMaskIntoConstraints = NO;
_priceLabel.textAlignment = NSTextAlignmentRight;
[_priceLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
......@@ -70,9 +67,9 @@
[priceView addSubview:_priceLabel];
_comparePriceLabel = [[UILabel alloc] init];
_comparePriceLabel.textColor = [BUYTheme comparePriceTextColor];
_comparePriceLabel.textColor = [Theme comparePriceTextColor];
_comparePriceLabel.textAlignment = NSTextAlignmentRight;
_comparePriceLabel.font = [BUYTheme productComparePriceFont];
_comparePriceLabel.font = [Theme productComparePriceFont];
_comparePriceLabel.translatesAutoresizingMaskIntoConstraints = NO;
[_comparePriceLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
[_comparePriceLabel setContentHuggingPriority:UILayoutPriorityDefaultLow forAxis:UILayoutConstraintAxisHorizontal];
......@@ -105,14 +102,14 @@
self.priceLabel.text = [currencyFormatter stringFromNumber:productVariant.price];
}
if (productVariant.available == YES && productVariant.compareAtPrice) {
if (productVariant.availableValue == YES && productVariant.compareAtPrice) {
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:[currencyFormatter stringFromNumber:productVariant.compareAtPrice]
attributes:@{NSStrikethroughStyleAttributeName: @(NSUnderlineStyleSingle)}];
self.comparePriceLabel.attributedText = attributedString;
self.comparePriceLabel.textColor = [BUYTheme comparePriceTextColor];
self.comparePriceLabel.textColor = [Theme comparePriceTextColor];
} else if (productVariant.available == NO) {
self.comparePriceLabel.text = @"Sold Out";
self.comparePriceLabel.textColor = [BUYTheme variantSoldOutTextColor];
self.comparePriceLabel.text = NSLocalizedString(@"Sold Out", @"Sold out text displayed on product view");
self.comparePriceLabel.textColor = [Theme variantSoldOutTextColor];
} else {
self.comparePriceLabel.attributedText = nil;
}
......@@ -121,12 +118,10 @@
[self layoutIfNeeded];
}
- (void)setTheme:(BUYTheme *)theme
- (void)setBackgroundColor:(UIColor *)backgroundColor
{
_theme = theme;
self.backgroundColor = [theme backgroundColor];
[super setBackgroundColor:backgroundColor];
self.titleLabel.backgroundColor = self.priceLabel.backgroundColor = self.comparePriceLabel.backgroundColor = self.backgroundColor;
self.titleLabel.textColor = [theme productTitleColor];
}
- (void)tintColorDidChange
......@@ -135,4 +130,9 @@
self.priceLabel.textColor = self.tintColor;
}
- (void)setProductTitleColor:(UIColor*)color
{
self.titleLabel.textColor = color;
}
@end
//
// BUYProductImageCollectionViewCell.h
// ProductImageCell.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,17 +25,17 @@
//
@import UIKit;
@class BUYImageView;
@class AsyncImageView;
/**
* A custom collection view cell for the BUYProductViewController's product image(s)
*/
@interface BUYProductImageCollectionViewCell : UICollectionViewCell
@interface ProductImageCell : UICollectionViewCell
/**
* The image view containing a product image
*/
@property (nonatomic, strong) BUYImageView *productImageView;
@property (nonatomic, strong) AsyncImageView *productImageView;
/**
* The height to display the product image
......
//
// BUYProductImageCollectionViewCell.m
// ProductImageCell.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,10 +24,10 @@
// THE SOFTWARE.
//
#import "BUYProductImageCollectionViewCell.h"
#import "BUYImageView.h"
#import "ProductImageCell.h"
#import "AsyncImageView.h"
@implementation BUYProductImageCollectionViewCell
@implementation ProductImageCell
- (instancetype)initWithFrame:(CGRect)frame
{
......@@ -38,7 +38,7 @@
self.contentView.backgroundColor = [UIColor clearColor];
_productImageView = [[BUYImageView alloc] init];
_productImageView = [[AsyncImageView alloc] init];
_productImageView.clipsToBounds = YES;
_productImageView.translatesAutoresizingMaskIntoConstraints = NO;
_productImageView.backgroundColor = [UIColor clearColor];
......
//
// BUYProductVariantCell.h
// ProductVariantCell.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,13 +25,12 @@
//
@import UIKit;
#import "BUYTheme.h"
@class BUYProductVariant;
@import Buy;
/**
* Table view cell containing the product's variant options
*/
@interface BUYProductVariantCell : UITableViewCell <BUYThemeable>
@interface ProductVariantCell : UITableViewCell
/**
* Set the options for a product variant
......@@ -40,4 +39,6 @@
*/
- (void)setOptionsForProductVariant:(BUYProductVariant *)productVariant;
- (void)setSelectedBackgroundViewBackgroundColor:(UIColor *)selectedBackgroundViewBackgroundColor UI_APPEARANCE_SELECTOR;
@end
//
// BUYProductVariantCell.m
// ProductVariantCell.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,23 +24,24 @@
// THE SOFTWARE.
//
#import "BUYProductVariantCell.h"
#import "BUYVariantOptionView.h"
#import "BUYProductVariant.h"
#import "BUYOptionValue.h"
#import "BUYImageKit.h"
#import "DisclosureIndicatorView.h"
#import "ImageKit.h"
#import "ProductVariantCell.h"
#import "Theme+Additions.h"
#import "VariantOptionView.h"
@interface BUYProductVariantCell ()
@property (nonatomic, strong) BUYVariantOptionView *optionView1;
@property (nonatomic, strong) BUYVariantOptionView *optionView2;
@property (nonatomic, strong) BUYVariantOptionView *optionView3;
@interface ProductVariantCell ()
@property (nonatomic, strong) VariantOptionView *optionView1;
@property (nonatomic, strong) VariantOptionView *optionView2;
@property (nonatomic, strong) VariantOptionView *optionView3;
@property (nonatomic, strong) NSArray *disclosureConstraints;
@property (nonatomic, strong) NSArray *noDisclosureConstraints;
@property (nonatomic, strong) UIImageView *disclosureIndicatorImageView;
@property (nonatomic, strong) BUYTheme *theme;
@property (nonatomic, strong) DisclosureIndicatorView *disclosureIndicatorImageView;
@end
@implementation BUYProductVariantCell
@implementation ProductVariantCell
CGFloat const buttonWidth = 10.0f;
......@@ -53,22 +54,22 @@ CGFloat const buttonWidth = 10.0f;
UIView *backgroundView = [[UIView alloc] init];
[self setSelectedBackgroundView:backgroundView];
_optionView1 = [[BUYVariantOptionView alloc] init];
_optionView1 = [[VariantOptionView alloc] init];
_optionView1.translatesAutoresizingMaskIntoConstraints = NO;
[_optionView1 setContentCompressionResistancePriority:UILayoutPriorityFittingSizeLevel forAxis:UILayoutConstraintAxisHorizontal];
[self.contentView addSubview:_optionView1];
_optionView2 = [[BUYVariantOptionView alloc] init];
_optionView2 = [[VariantOptionView alloc] init];
_optionView2.translatesAutoresizingMaskIntoConstraints = NO;
[_optionView3 setContentCompressionResistancePriority:UILayoutPriorityFittingSizeLevel forAxis:UILayoutConstraintAxisHorizontal];
[self.contentView addSubview:_optionView2];
_optionView3 = [[BUYVariantOptionView alloc] init];
_optionView3 = [[VariantOptionView alloc] init];
_optionView3.translatesAutoresizingMaskIntoConstraints = NO;
[_optionView3 setContentCompressionResistancePriority:UILayoutPriorityFittingSizeLevel forAxis:UILayoutConstraintAxisHorizontal];
[self.contentView addSubview:_optionView3];
_disclosureIndicatorImageView = [[UIImageView alloc] init];
_disclosureIndicatorImageView = [[DisclosureIndicatorView alloc] init];
_disclosureIndicatorImageView.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:_disclosureIndicatorImageView];
......@@ -97,7 +98,7 @@ CGFloat const buttonWidth = 10.0f;
- (void)setOptionsForProductVariant:(BUYProductVariant *)productVariant
{
NSArray *productOptions = productVariant.options;
NSArray *productOptions = [productVariant.options allObjects];
switch (productVariant.options.count) {
case 3:
......@@ -137,16 +138,9 @@ CGFloat const buttonWidth = 10.0f;
}
}
- (void)setTheme:(BUYTheme *)theme
- (void)setSelectedBackgroundViewBackgroundColor:(UIColor *)selectedBackgroundViewBackgroundColor
{
_theme = theme;
self.backgroundColor = [theme backgroundColor];
self.selectedBackgroundView.backgroundColor = [theme selectedBackgroundColor];
self.disclosureIndicatorImageView.image = [BUYImageKit imageOfDisclosureIndicatorImageWithFrame:CGRectMake(0, 0, buttonWidth, 16) color:[theme disclosureIndicatorColor]];
[self.optionView1 setTheme:theme];
[self.optionView2 setTheme:theme];
[self.optionView3 setTheme:theme];
self.selectedBackgroundView.backgroundColor = selectedBackgroundViewBackgroundColor;
}
@end
//
// BUYProductView.h
// ProductView.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,18 +25,16 @@
//
@import UIKit;
@class BUYProductViewHeader;
@class BUYProductViewHeaderBackgroundImageView;
@class BUYProductViewFooter;
@class BUYGradientView;
@class BUYTheme;
@class BUYImage;
@class BUYProduct;
@import Buy;
@class ActionableFooterView;
@class GradientView;
@class ProductViewHeader;
@class HeaderBackgroundView;
/**
* The BUYProductViewController's main view, containing everything needed to display the UI for the product
*/
@interface BUYProductView : UIView
@interface ProductView : UIView
/**
* The table view containg the product's image(s) in the tableHeaderView, title, price,
......@@ -64,24 +62,19 @@
/**
* The tableHeaderView containting the product image(s) (if available)
*/
@property (nonatomic, strong) BUYProductViewHeader *productViewHeader;
@property (nonatomic, strong) BUYProductViewHeaderBackgroundImageView *backgroundImageView;
@property (nonatomic, strong) ProductViewHeader *productViewHeader;
@property (nonatomic, strong) HeaderBackgroundView *backgroundImageView;
/**
* The footer view containing the Checkout button, and - if enabled - Apple Pay button.
*/
@property (nonatomic, strong) BUYProductViewFooter *productViewFooter;
@property (nonatomic, strong) ActionableFooterView *productViewFooter;
/**
* A gradient view that sits at the top of the product images (if available).
* This view is invisible when the navigation bar is visible.
*/
@property (nonatomic, strong) BUYGradientView *topGradientView;
/**
* The theme of the product view.
*/
@property (nonatomic, weak) BUYTheme *theme;
@property (nonatomic, strong) GradientView *topGradientView;
/**
* Helps determine logic for setting up product images in the BUYProductViewController
......@@ -91,14 +84,14 @@
/**
* Initializer for the product view using a rect, product to display and theme
*
* @param rect The rect is needed for the UICollectionView in the BUYProductViewHeader to setup the cell's bounds
* @param rect The rect is needed for the UICollectionView in the ProductViewHeader to setup the cell's bounds
* @param product The product to display in the product view. Only used in the initializer to
* @param theme The theme for the product view
* @param showApplePaySetup Show Apple Pay button with 'Set Up Apple Pay' text as determined by the presenter
*
* @return An instance of the BUYProductView
* @return An instance of the ProductView
*/
- (instancetype)initWithFrame:(CGRect)rect product:(BUYProduct*)product theme:(BUYTheme*)theme shouldShowApplePaySetup:(BOOL)showApplePaySetup;
- (instancetype)initWithFrame:(CGRect)rect product:(BUYProduct*)product shouldShowApplePaySetup:(BOOL)showApplePaySetup;
/**
* The BUYProductViewController is the UITableViewDelegate, so it receives the UIScrollView delegate method calls.
......@@ -138,4 +131,6 @@
*/
- (void)setTopInset:(CGFloat)topInset;
- (void)setShowsProductImageBackground:(BOOL)showsProductImageBackground UI_APPEARANCE_SELECTOR;
@end
//
// BUYProductView.m
// ProductView.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,38 +24,32 @@
// THE SOFTWARE.
//
#import "BUYProductView.h"
#import "BUYProductViewHeader.h"
#import "BUYProductViewHeaderBackgroundImageView.h"
#import "BUYProductViewFooter.h"
#import "BUYGradientView.h"
#import "BUYProductVariantCell.h"
#import "BUYProductDescriptionCell.h"
#import "BUYProductHeaderCell.h"
#import "BUYImage.h"
#import "BUYImageView.h"
#import "BUYProduct.h"
#import "BUYProductViewErrorView.h"
#import "BUYTheme.h"
#import "BUYTheme+Additions.h"
#import "ProductView.h"
#import "ProductViewHeader.h"
#import "HeaderBackgroundView.h"
#import "ActionableFooterView.h"
#import "GradientView.h"
#import "ProductVariantCell.h"
#import "ProductDescriptionCell.h"
#import "ProductHeaderCell.h"
#import "AsyncImageView.h"
#import "ErrorView.h"
#import "Theme+Additions.h"
@interface BUYProductView ()
@interface ProductView ()
@property (nonatomic, strong) UILabel *poweredByShopifyLabel;
@property (nonatomic, strong) NSLayoutConstraint *poweredByShopifyLabelConstraint;
@property (nonatomic, strong) BUYProductViewErrorView *errorView;
@property (nonatomic, strong) ErrorView *errorView;
@property (nonatomic, strong) NSLayoutConstraint *topInsetConstraint;
@end
@implementation BUYProductView
@implementation ProductView
- (instancetype)initWithFrame:(CGRect)rect product:(BUYProduct*)product theme:(BUYTheme*)theme shouldShowApplePaySetup:(BOOL)showApplePaySetup
- (instancetype)initWithFrame:(CGRect)rect product:(BUYProduct*)product shouldShowApplePaySetup:(BOOL)showApplePaySetup
{
self = [super initWithFrame:rect];
if (self) {
_backgroundImageView = [[BUYProductViewHeaderBackgroundImageView alloc] initWithTheme:theme];
_backgroundImageView.hidden = theme.showsProductImageBackground == NO;
_backgroundImageView = [[HeaderBackgroundView alloc] init];
_backgroundImageView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_backgroundImageView];
......@@ -75,7 +69,6 @@
constant:0.0]];
_stickyFooterView = [UIView new];
_stickyFooterView.backgroundColor = [theme backgroundColor];
_stickyFooterView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_stickyFooterView];
......@@ -114,9 +107,9 @@
_tableView.layoutMargins = UIEdgeInsetsMake(_tableView.layoutMargins.top, kBuyPaddingExtraLarge, _tableView.layoutMargins.bottom, kBuyPaddingMedium);
[self addSubview:_tableView];
[_tableView registerClass:[BUYProductHeaderCell class] forCellReuseIdentifier:@"headerCell"];
[_tableView registerClass:[BUYProductVariantCell class] forCellReuseIdentifier:@"variantCell"];
[_tableView registerClass:[BUYProductDescriptionCell class] forCellReuseIdentifier:@"descriptionCell"];
[_tableView registerClass:[ProductHeaderCell class] forCellReuseIdentifier:@"headerCell"];
[_tableView registerClass:[ProductVariantCell class] forCellReuseIdentifier:@"variantCell"];
[_tableView registerClass:[ProductDescriptionCell class] forCellReuseIdentifier:@"descriptionCell"];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_tableView]|"
options:0
......@@ -138,35 +131,13 @@
CGFloat size = MIN(CGRectGetWidth(rect), CGRectGetHeight(rect));
if ([product.images count] > 0) {
_productViewHeader = [[BUYProductViewHeader alloc] initWithFrame:CGRectMake(0, 0, size, size) theme:theme];
_productViewHeader = [[ProductViewHeader alloc] initWithFrame:CGRectMake(0, 0, size, size)];
_tableView.tableHeaderView = self.productViewHeader;
} else {
_tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 1)];
}
_poweredByShopifyLabel = [[UILabel alloc] init];
_poweredByShopifyLabel.translatesAutoresizingMaskIntoConstraints = NO;
_poweredByShopifyLabel.backgroundColor = [UIColor clearColor];
_poweredByShopifyLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote];
_poweredByShopifyLabel.text = @"Powered by Shopify";
_poweredByShopifyLabel.textAlignment = NSTextAlignmentCenter;
[self addSubview:_poweredByShopifyLabel];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_poweredByShopifyLabel]|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(_poweredByShopifyLabel)]];
_poweredByShopifyLabelConstraint = [NSLayoutConstraint constraintWithItem:_poweredByShopifyLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0.0];
[self addConstraint:_poweredByShopifyLabelConstraint];
_productViewFooter = [[BUYProductViewFooter alloc] initWithTheme:theme showApplePaySetup:showApplePaySetup];
_productViewFooter = [ActionableFooterView new];
_productViewFooter.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_productViewFooter];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_productViewFooter]|"
......@@ -179,8 +150,8 @@
views:NSDictionaryOfVariableBindings(_productViewFooter)]];
if (_productViewHeader) {
_topGradientView = [[BUYGradientView alloc] init];
_topGradientView.topColor = [BUYTheme topGradientViewTopColor];
_topGradientView = [[GradientView alloc] init];
_topGradientView.topColor = [Theme topGradientViewTopColor];
_topGradientView.translatesAutoresizingMaskIntoConstraints = NO;
_topGradientView.userInteractionEnabled = NO;
[self addSubview:_topGradientView];
......@@ -194,8 +165,6 @@
metrics:@{ @"height" : @(kBuyTopGradientViewHeight) }
views:NSDictionaryOfVariableBindings(_topGradientView)]];
}
self.theme = theme;
}
return self;
}
......@@ -206,17 +175,6 @@
[self setInsets:UIEdgeInsetsMake(self.tableView.contentInset.top, self.tableView.contentInset.left, CGRectGetHeight(self.bounds) - CGRectGetMinY(self.productViewFooter.frame), self.tableView.contentInset.right) appendToCurrentInset:NO];
}
- (void)setTheme:(BUYTheme *)theme
{
_theme = theme;
self.tintColor = _theme.tintColor;
self.tableView.separatorColor = [theme separatorColor];
self.backgroundColor = [theme backgroundColor];
self.stickyFooterView.backgroundColor = self.backgroundColor;
self.backgroundImageView.hidden = theme.showsProductImageBackground == NO;
self.poweredByShopifyLabel.textColor = self.tableView.separatorColor;
}
- (void)updateBackgroundImage:(NSArray *)images
{
if ([images count] > 0) {
......@@ -225,7 +183,7 @@
page = (int)(self.productViewHeader.collectionView.contentOffset.x / self.productViewHeader.collectionView.frame.size.width);
}
[self.productViewHeader setCurrentPage:page];
BUYImage *image = images[page];
BUYImageLink *image = images[page];
[self.backgroundImageView setBackgroundProductImage:image];
}
}
......@@ -253,17 +211,14 @@
CGFloat opaqueOffset = CGRectGetHeight(self.productViewHeader.bounds);
CGFloat whiteStartingOffset = opaqueOffset - CGRectGetHeight(self.topGradientView.bounds);
self.topGradientView.alpha = -(scrollView.contentOffset.y - whiteStartingOffset) / (opaqueOffset - whiteStartingOffset);
CGFloat labelOffset = scrollView.contentSize.height - (scrollView.contentOffset.y + CGRectGetHeight(scrollView.bounds));
self.poweredByShopifyLabelConstraint.constant = (CGRectGetHeight(scrollView.bounds) / 3) + labelOffset;
}
#pragma mark - Error Handling
- (BUYProductViewErrorView *)errorView
- (ErrorView *)errorView
{
if (_errorView == nil) {
_errorView = [[BUYProductViewErrorView alloc] initWithTheme:self.theme];
_errorView = [[ErrorView alloc] init];
_errorView.alpha = 0;
_errorView.translatesAutoresizingMaskIntoConstraints = NO;
[self insertSubview:_errorView belowSubview:self.productViewFooter];
......@@ -298,36 +253,9 @@
- (void)showErrorWithMessage:(NSString*)errorMessage
{
self.errorView.errorLabel.text = errorMessage;
[NSLayoutConstraint deactivateConstraints:@[self.errorView.hiddenConstraint]];
[NSLayoutConstraint activateConstraints:@[self.errorView.visibleConstraint]];
[UIView animateWithDuration:0.3f
delay:0
usingSpringWithDamping:0.8f
initialSpringVelocity:10
options:0
animations:^{
self.errorView.alpha = 1;
[self.errorView layoutIfNeeded];
}
completion:^(BOOL finished) {
[NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(removeErrorView) userInfo:nil repeats:NO];
}];
}
- (void)removeErrorView
{
[NSLayoutConstraint deactivateConstraints:@[self.errorView.visibleConstraint]];
[NSLayoutConstraint activateConstraints:@[self.errorView.hiddenConstraint]];
[UIView animateWithDuration:0.3f
animations:^{
self.errorView.alpha = 0;
[self.errorView layoutIfNeeded];
}
completion:^(BOOL finished) {
[self.errorView removeFromSuperview];
self.errorView = nil;
}];
[self.errorView presentErrorViewWithMessage:errorMessage completion:^{
self.errorView = nil;
}];
}
- (void)setInsets:(UIEdgeInsets)edgeInsets appendToCurrentInset:(BOOL)appendToCurrentInset
......@@ -344,4 +272,16 @@
self.topInsetConstraint.constant = topInset;
}
#pragma mark - Appearance
- (void)setBackgroundColor:(UIColor *)backgroundColor {
[super setBackgroundColor:backgroundColor];
_stickyFooterView.backgroundColor = backgroundColor;
}
- (void)setShowsProductImageBackground:(BOOL)showsProductImageBackground
{
_backgroundImageView.hidden = showsProductImageBackground == NO;
}
@end
//
// BUYProductViewController.h
// ProductViewController.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,11 +24,13 @@
// THE SOFTWARE.
//
#import "BUYTheme.h"
#import "BUYViewController.h"
#import "BUYClient.h"
@import UIKit;
@import Buy;
@interface BUYProductViewController : BUYViewController <BUYThemeable>
#import "Theme.h"
#import "PaymentViewController.h"
@interface ProductViewController : PaymentViewController
/**
* Creates a BUYProductViewController with a BUYClient and a theme
......@@ -37,20 +39,21 @@
* use `initWithClient:`
*
* @param client A BUYClient configured to your shop
* @param theme A BUYTheme
* @param theme A Theme
*
* @return A BUYViewController
* @return A PaymentViewController
*/
- (instancetype)initWithClient:(BUYClient *)client theme:(BUYTheme *)theme;
- (instancetype)initWithClient:(BUYClient *)client theme:(Theme *)theme;
/**
* Loads the product details
* Creates a BUYProductViewController with a BUYClient and a cart
*
* @param client A BUYClient configured to your shop
* @param cart A cart that enables a "Add to cart" button instead of the web checout button
*
* @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
* @return A PaymentViewController with an "Add to cart" button
*/
- (void)loadProduct:(NSString *)productId completion:(void (^)(BOOL success, NSError *error))completion;
- (instancetype)initWithClient:(BUYClient *)client cart:(BUYCart *)cart;
/**
* Alternative method when setting the product (and optionally, shop) directly on the view controller
......
//
// BUYProductViewHeader.h
// ProductViewHeader.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,16 +25,17 @@
//
@import UIKit;
@class BUYImageView;
@import Buy;
@class AsyncImageView;
@class BUYProductVariant;
@class BUYTheme;
@class BUYProductViewHeaderOverlay;
@class HeaderOverlayView;
/**
* The tableHeaderView containing a horizontally scrolling collection view
* that display product images.
*/
@interface BUYProductViewHeader : UIView
@interface ProductViewHeader : UIView
/**
* A horiztonally scrolling collection view containing product images.
......@@ -45,7 +46,7 @@
* An overlay view containing effects views (light or dark view and a UIVisualEffectsView) that becomes
* visible as the user scrolls the contents up. This provides a more seamless transition for the navigation bar.
*/
@property (nonatomic, strong) BUYProductViewHeaderOverlay *productViewHeaderOverlay;
@property (nonatomic, strong) HeaderOverlayView *productViewHeaderOverlay;
/**
* Initializer with a frame to setup the product image collection view and theme the header
......@@ -55,11 +56,11 @@
*
* @return The product view header to display in the BUYProductViewController's table view tableHeaderView
*/
- (instancetype)initWithFrame:(CGRect)frame theme:(BUYTheme*)theme;
- (instancetype)initWithFrame:(CGRect)frame;
/**
* A method to set the content offset of the table view and calculate the height of the image
* used to set the correct height and offset for the stickyFooterView in the BUYProductView.
* used to set the correct height and offset for the stickyFooterView in the ProductView.
*
* @param scrollView The table view being scrolled
*
......
//
// BUYProductViewHeader.m
// ProductViewHeader.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,29 +24,26 @@
// THE SOFTWARE.
//
#import "BUYProductViewHeader.h"
#import "BUYImageView.h"
#import "BUYGradientView.h"
#import "BUYProductImageCollectionViewCell.h"
#import "BUYImage.h"
#import "BUYProductVariant.h"
#import "BUYTheme.h"
#import "BUYTheme+Additions.h"
#import "BUYProductViewHeaderOverlay.h"
#import "ProductViewHeader.h"
#import "AsyncImageView.h"
#import "GradientView.h"
#import "ProductImageCell.h"
#import "Theme+Additions.h"
#import "HeaderOverlayView.h"
@interface BUYProductViewHeader ()
@interface ProductViewHeader ()
@property (nonatomic, strong) UIPageControl *pageControl;
@property (nonatomic, strong) UIView *bottomGradientContainerView;
@property (nonatomic, strong) BUYGradientView *bottomGradientView;
@property (nonatomic, strong) GradientView *bottomGradientView;
@property (nonatomic, strong) NSLayoutConstraint *bottomGradientViewLayoutConstraintHeight;
@property (nonatomic, strong) NSLayoutConstraint *bottomGradientViewBottomContraint;
@end
@implementation BUYProductViewHeader
@implementation ProductViewHeader
- (instancetype)initWithFrame:(CGRect)frame theme:(BUYTheme*)theme
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
......@@ -63,7 +60,7 @@
_collectionView.pagingEnabled = YES;
_collectionView.clipsToBounds = NO;
_collectionView.translatesAutoresizingMaskIntoConstraints = NO;
[_collectionView registerClass:[BUYProductImageCollectionViewCell class] forCellWithReuseIdentifier:@"Cell"];
[_collectionView registerClass:[ProductImageCell class] forCellWithReuseIdentifier:@"Cell"];
[self addSubview:_collectionView];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_collectionView]|"
......@@ -101,7 +98,7 @@
constant:kBuyBottomGradientHeightWithoutPageControl];
[self addConstraint:_bottomGradientViewLayoutConstraintHeight];
_bottomGradientView = [[BUYGradientView alloc] init];
_bottomGradientView = [[GradientView alloc] init];
_bottomGradientView.userInteractionEnabled = NO;
_bottomGradientView.topColor = [UIColor clearColor];
_bottomGradientView.bottomColor = [UIColor colorWithWhite:0 alpha:0.05f];
......@@ -160,7 +157,7 @@
multiplier:1.0
constant:kBuyPageControlHeight]];
_productViewHeaderOverlay = [[BUYProductViewHeaderOverlay alloc] initWithTheme:theme];
_productViewHeaderOverlay = [[HeaderOverlayView alloc] init];
_productViewHeaderOverlay.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_productViewHeaderOverlay];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_productViewHeaderOverlay]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_productViewHeaderOverlay)]];
......@@ -192,7 +189,7 @@
CGRect visibleRect = (CGRect){.origin = self.collectionView.contentOffset, .size = self.collectionView.bounds.size};
CGPoint visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect));
NSIndexPath *visibleIndexPath = [self.collectionView indexPathForItemAtPoint:visiblePoint];
BUYProductImageCollectionViewCell *cell = (BUYProductImageCollectionViewCell*)[self.collectionView cellForItemAtIndexPath:visibleIndexPath];
ProductImageCell *cell = (ProductImageCell*)[self.collectionView cellForItemAtIndexPath:visibleIndexPath];
if (cell) {
[cell setContentOffset:scrollView.contentOffset];
return cell.productImageViewConstraintHeight.constant;
......@@ -206,7 +203,7 @@
{
[self setNumberOfPages:[images count]];
if (CGSizeEqualToSize(self.collectionView.contentSize, CGSizeZero) == NO) {
[images enumerateObjectsUsingBlock:^(BUYImage *image, NSUInteger i, BOOL *stop) {
[images enumerateObjectsUsingBlock:^(BUYImageLink *image, NSUInteger i, BOOL *stop) {
for (NSNumber *variantId in image.variantIds) {
if ([variantId isEqualToNumber:productVariant.identifier]) {
[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
......
//
// BUYNavigationController.h
// ProductViewNavigationController.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,10 +24,9 @@
// THE SOFTWARE.
//
@import UIKit;
#import "BUYTheme.h"
#import "NavigationController.h"
@protocol BUYNavigationControllerDelegate <NSObject>
@protocol ProductViewNavigationControllerDelegate <NSObject>
/**
* Delegate callback when the BUYProductViewController will dismiss
......@@ -45,10 +44,7 @@
@end
/**
* A custom navigation controller used in the BUYProductViewController, adding a close button and the ability to theme the navigation bar
*/
@interface BUYNavigationController : UINavigationController <BUYThemeable>
@interface ProductViewNavigationController : NavigationController
/**
* The close button has two styles; white or tint color. This methods updates the button image with the preferred style.
......@@ -60,9 +56,8 @@
- (void)updateCloseButtonImageWithTintColor:(BOOL)tintColor duration:(CGFloat)duration;
/**
* The BUYNavigationControllerDelegate
* The SmoothNavigationControllerDelegate
*/
@property (nonatomic, weak) id <BUYNavigationControllerDelegate> navigationDelegate;
@property (nonatomic, weak) id <ProductViewNavigationControllerDelegate> navigationDelegate;
@end
//
// BUYNavigationController.m
// ProductViewNavigationController.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,16 +24,12 @@
// THE SOFTWARE.
//
#import "BUYNavigationController.h"
#import "BUYImageKit.h"
#import "BUYTheme+Additions.h"
#import "BUYProductViewController.h"
#import "ProductViewNavigationController.h"
#import "ImageKit.h"
#import "Theme+Additions.h"
#import "ProductViewController.h"
@interface BUYNavigationController ()
@property (nonatomic, strong) BUYTheme *theme;
@end
@implementation BUYNavigationController
@implementation ProductViewNavigationController
- (instancetype)initWithRootViewController:(UIViewController *)rootViewController
{
......@@ -45,18 +41,23 @@
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:closeButton];
self.topViewController.navigationItem.leftBarButtonItem = barButtonItem;
if ([[UINavigationBar class] respondsToSelector:@selector(appearanceWhenContainedInInstancesOfClasses:)]) {
[[UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[[BUYNavigationController class]]] setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
[[UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[[ProductViewNavigationController class]]] setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
} else {
[[UINavigationBar appearanceWhenContainedIn:[BUYNavigationController class], nil] setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
[[UINavigationBar appearanceWhenContainedIn:[ProductViewNavigationController class], nil] setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
}
[self updateCloseButtonImageWithTintColor:YES duration:0];
return self;
}
- (void)updateCloseButtonImageWithTintColor:(BOOL)tintColor duration:(CGFloat)duration
{
UIButton *button = (UIButton*)self.topViewController.navigationItem.leftBarButtonItem.customView;
UIImage *newButtonImage = [BUYImageKit imageOfProductViewCloseImageWithFrame:button.bounds color:tintColor ? self.theme.tintColor : [UIColor whiteColor] hasShadow:tintColor == NO];
UIImage *newButtonImage = [ImageKit imageOfProductViewCloseImageWithFrame:button.bounds color:[UIColor whiteColor] hasShadow:tintColor == NO];
if (tintColor) {
newButtonImage = [newButtonImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
}
[UIView transitionWithView:button.imageView
duration:duration
options:(UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionBeginFromCurrentState)
......@@ -86,18 +87,6 @@
return self.topViewController.shouldAutorotate;
}
- (void)setTheme:(BUYTheme *)theme
{
_theme = theme;
self.navigationBar.barStyle = [theme navigationBarStyle];
[self updateCloseButtonImageWithTintColor:NO duration:0];
if ([[UINavigationBar class] respondsToSelector:@selector(appearanceWhenContainedInInstancesOfClasses:)]) {
[[UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[[BUYNavigationController class]]] setTitleTextAttributes:@{ NSForegroundColorAttributeName: [theme navigationBarTitleColor] }];
} else {
[[UINavigationBar appearanceWhenContainedIn:[BUYNavigationController class], nil] setTitleTextAttributes:@{ NSForegroundColorAttributeName: [theme navigationBarTitleColor] }];
}
}
-(UIViewController *)childViewControllerForStatusBarStyle
{
return [self childViewController];
......@@ -110,7 +99,7 @@
-(UIViewController*)childViewController
{
if ([self.visibleViewController isKindOfClass:[BUYProductViewController class]] == NO) {
if ([self.visibleViewController isKindOfClass:[ProductViewController class]] == NO) {
return self.viewControllers[0];
}
return self.visibleViewController;
......
//
// BUYPresentationControllerWithNavigationController.h
// ProductViewPresentationController.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,16 +25,15 @@
//
@import UIKit;
#import "BUYTheme.h"
@protocol BUYPresentationControllerWithNavigationControllerDelegate;
@protocol ProductViewNavigationControllerDelegate;
/**
* Initialized the BUYProductViewController inside a navigation controller (`BUYNavigationController`).
* Initialized the BUYProductViewController inside a navigation controller (`ProductViewNavigationController`).
*/
@interface BUYPresentationControllerWithNavigationController : UIPresentationController <UIAdaptivePresentationControllerDelegate, BUYThemeable>
@interface ProductViewPresentationController : UIPresentationController <UIAdaptivePresentationControllerDelegate>
@property (nonatomic, weak) id <BUYNavigationControllerDelegate> navigationDelegate;
@property (nonatomic, weak) id <ProductViewNavigationControllerDelegate> navigationDelegate;
/**
* The desired presentation style
......
//
// BUYPresentationControllerWithNavigationController.m
// ProductViewPresentationController.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,23 +24,16 @@
// THE SOFTWARE.
//
#import "BUYNavigationController.h"
#import "BUYOptionSelectionNavigationController.h"
#import "BUYPresentationControllerWithNavigationController.h"
#import "BUYImageKit.h"
#import "OptionSelectionNavigationController.h"
#import "ProductViewPresentationController.h"
#import "ProductViewNavigationController.h"
@interface BUYPresentationControllerWithNavigationController ()
@property (nonatomic, strong) BUYTheme *theme;
@end
@implementation BUYPresentationControllerWithNavigationController
@implementation ProductViewPresentationController
- (UIViewController *)presentationController:(UIPresentationController *)controller viewControllerForAdaptivePresentationStyle:(UIModalPresentationStyle)style
{
BUYNavigationController *navigationController = [[BUYNavigationController alloc] initWithRootViewController:controller.presentedViewController];
ProductViewNavigationController *navigationController = [[ProductViewNavigationController alloc] initWithRootViewController:controller.presentedViewController];
navigationController.navigationDelegate = self.navigationDelegate;
[navigationController setTheme:self.theme];
return navigationController;
}
......@@ -59,11 +52,4 @@
return (traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) ? UIModalPresentationFullScreen : UIModalPresentationFormSheet;
}
- (void)setTheme:(BUYTheme *)theme
{
_theme = theme;
BUYNavigationController *navigationController = (BUYNavigationController*)self.presentedViewController;
[navigationController setTheme:theme];
}
@end
//
// BUYVariantOptionBreadCrumbsView.h
// OptionBreadCrumbsView.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,12 +25,11 @@
//
@import UIKit;
#import "BUYTheme.h"
/**
* A view containing the current selection of variant option values that sits below the navigation controller for the variant selection.
*/
@interface BUYVariantOptionBreadCrumbsView : UIView <BUYThemeable>
@interface OptionBreadCrumbsView : UIView
/**
* Auto Layout constraint for setting the bread crumbs as hidden
......@@ -49,4 +48,9 @@
*/
- (void)setSelectedBuyOptionValues:(NSArray*)optionValues;
/**
* The color of the labels
*/
-(void)setVariantOptionTextColor:(UIColor*)color UI_APPEARANCE_SELECTOR;
@end
//
// BUYVariantOptionBreadCrumbsView.m
// OptionBreadCrumbsView.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,10 +24,10 @@
// THE SOFTWARE.
//
#import "BUYVariantOptionBreadCrumbsView.h"
#import "BUYTheme+Additions.h"
#import "OptionBreadCrumbsView.h"
#import "Theme+Additions.h"
@interface BUYVariantOptionBreadCrumbsView ()
@interface OptionBreadCrumbsView ()
@property (nonatomic, strong) UILabel *optionOneLabel;
@property (nonatomic, strong) UILabel *optionTwoLabel;
......@@ -37,7 +37,7 @@
@end
@implementation BUYVariantOptionBreadCrumbsView
@implementation OptionBreadCrumbsView
- (instancetype)init
{
......@@ -47,15 +47,13 @@
_optionOneLabel = [UILabel new];
_optionOneLabel.translatesAutoresizingMaskIntoConstraints = NO;
_optionOneLabel.font = [BUYTheme variantBreadcrumbsFont];
_optionOneLabel.textColor = [BUYTheme variantBreadcrumbsTextColor];
_optionOneLabel.text = @"Selected: ";
_optionOneLabel.font = [Theme variantBreadcrumbsFont];
_optionOneLabel.text = NSLocalizedString(@"Selected: ", @"Prefix for selected option value in variant selector");
[self addSubview:_optionOneLabel];
_optionTwoLabel = [UILabel new];
_optionTwoLabel.translatesAutoresizingMaskIntoConstraints = NO;
_optionTwoLabel.font = [BUYTheme variantBreadcrumbsFont];
_optionTwoLabel.textColor = [BUYTheme variantBreadcrumbsTextColor];
_optionTwoLabel.font = [Theme variantBreadcrumbsFont];
_optionTwoLabel.alpha = 0;
[_optionTwoLabel setContentHuggingPriority:UILayoutPriorityFittingSizeLevel forAxis:UILayoutConstraintAxisHorizontal];
[self addSubview:_optionTwoLabel];
......@@ -78,11 +76,6 @@
return self;
}
- (void)setTheme:(BUYTheme *)theme
{
self.backgroundColor = [theme variantBreadcrumbsBackground];
}
- (void)setSelectedBuyOptionValues:(NSArray*)optionValues
{
if ([optionValues count] == 1) {
......@@ -128,4 +121,16 @@
}];
}
-(void)setBackgroundColor:(UIColor *)backgroundColor
{
[super setBackgroundColor:backgroundColor];
self.optionOneLabel.backgroundColor = self.optionTwoLabel.backgroundColor = self.backgroundColor;
}
-(void)setVariantOptionTextColor:(UIColor*)color
{
self.optionOneLabel.textColor = self.optionTwoLabel.textColor = color;
}
@end
//
// BUYNavigationController.h
// OptionSelectionNavigationController.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,14 +25,13 @@
//
@import UIKit;
#import "BUYNavigationController.h"
#import "BUYTheme.h"
#import "BUYVariantOptionBreadCrumbsView.h"
#import "NavigationController.h"
#import "OptionBreadCrumbsView.h"
/**
* Custom navigation controller for variant option selection
*/
@interface BUYOptionSelectionNavigationController : BUYNavigationController <BUYThemeable>
@interface OptionSelectionNavigationController : NavigationController
/**
* Used to set whether to dismiss with dropping animation when variant selection is cancelled instead of confirmed
......@@ -42,6 +41,6 @@
/**
* The bread crumbs view for variant option selections
*/
@property (nonatomic, strong) BUYVariantOptionBreadCrumbsView *breadsCrumbsView;
@property (nonatomic, strong) OptionBreadCrumbsView *breadsCrumbsView;
@end
//
// BUYNavigationController.m
// OptionSelectionNavigationController.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,16 +24,15 @@
// THE SOFTWARE.
//
#import "BUYOptionSelectionNavigationController.h"
#import "BUYPresentationControllerForVariantSelection.h"
#import "BUYImageKit.h"
#import "BUYTheme+Additions.h"
#import "OptionSelectionNavigationController.h"
#import "VariantSelectionPresentationController.h"
#import "ImageKit.h"
@interface BUYOptionSelectionNavigationController () <UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning>
@interface OptionSelectionNavigationController () <UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning>
@end
@implementation BUYOptionSelectionNavigationController
@implementation OptionSelectionNavigationController
- (instancetype)initWithRootViewController:(UIViewController *)rootViewController
{
......@@ -46,18 +45,18 @@
self.view.clipsToBounds = YES;
// Add custom back button
UIImage *buttonImage = [[BUYImageKit imageOfVariantBackImageWithFrame:CGRectMake(0, 0, 12, 18)] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIImage *buttonImage = [[ImageKit imageOfVariantBackImageWithFrame:CGRectMake(0, 0, 12, 18)] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
if ([[UIBarButtonItem class] respondsToSelector:@selector(appearanceWhenContainedInInstancesOfClasses:)]) {
[[UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[BUYNavigationController class]]] setBackButtonBackgroundImage:[buttonImage resizableImageWithCapInsets:UIEdgeInsetsMake(0, 12, 0, 0)]
[[UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[NavigationController class]]] setBackButtonBackgroundImage:[buttonImage resizableImageWithCapInsets:UIEdgeInsetsMake(0, 12, 0, 0)]
forState:UIControlStateNormal
barMetrics:UIBarMetricsDefault];
} else {
[[UIBarButtonItem appearanceWhenContainedIn:[BUYNavigationController class], nil] setBackButtonBackgroundImage:[buttonImage resizableImageWithCapInsets:UIEdgeInsetsMake(0, 12, 0, 0)]
[[UIBarButtonItem appearanceWhenContainedIn:[NavigationController class], nil] setBackButtonBackgroundImage:[buttonImage resizableImageWithCapInsets:UIEdgeInsetsMake(0, 12, 0, 0)]
forState:UIControlStateNormal
barMetrics:UIBarMetricsDefault];
}
_breadsCrumbsView = [BUYVariantOptionBreadCrumbsView new];
_breadsCrumbsView = [OptionBreadCrumbsView new];
_breadsCrumbsView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:_breadsCrumbsView];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:_breadsCrumbsView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0]];
......@@ -71,19 +70,11 @@
return self;
}
- (void)setTheme:(BUYTheme *)theme
{
[self.breadsCrumbsView setTheme:theme];
self.navigationBar.barStyle = [theme navigationBarStyle];
[self.navigationBar setTitleTextAttributes:@{ NSForegroundColorAttributeName : [theme navigationBarTitleVariantSelectionColor] }];
self.navigationBar.tintColor = theme.tintColor;
}
#pragma mark - Transitioning Delegate Methods
- (UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source
{
BUYPresentationControllerForVariantSelection *presentationController = [[BUYPresentationControllerForVariantSelection alloc] initWithPresentedViewController:presented presentingViewController:presenting];
VariantSelectionPresentationController *presentationController = [[VariantSelectionPresentationController alloc] initWithPresentedViewController:presented presentingViewController:presenting];
return presentationController;
}
......@@ -126,7 +117,7 @@
UIView *dismissedView = [transitionContext viewForKey:UITransitionContextFromViewKey];
CGRect frame = dismissedView.frame;
CGAffineTransform transform;
BUYOptionSelectionNavigationController *optionSelectionNavigationController = (BUYOptionSelectionNavigationController *)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
OptionSelectionNavigationController *optionSelectionNavigationController = (OptionSelectionNavigationController *)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
if (optionSelectionNavigationController.dismissWithCancelAnimation) {
frame.origin.y += 150;
int angle = arc4random_uniform(20) - 10;
......
//
// BUYOptionSelectionViewController.h
// OptionSelectionViewController.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,12 +25,10 @@
//
@import UIKit;
#import "BUYTheme.h"
@import Buy;
@class OptionSelectionViewController;
@class BUYOptionValue;
@class BUYOptionSelectionViewController;
@protocol BUYOptionSelectionDelegate <NSObject>
@protocol OptionSelectionDelegate <NSObject>
/**
* Called when a user selected an option value
......@@ -38,21 +36,21 @@
* @param controller The BUYOptionSelectionViewController
* @param optionValue The selected BUYOptionValue
*/
- (void)optionSelectionController:(BUYOptionSelectionViewController *)controller didSelectOptionValue:(BUYOptionValue *)optionValue;
- (void)optionSelectionController:(OptionSelectionViewController *)controller didSelectOptionValue:(BUYOptionValue *)optionValue;
/**
* Called when a user pops the navigation controller and backs out of the current option
*
* @param controller The BUYOptionSelectionViewController
*/
- (void)optionSelectionControllerDidBackOutOfChoosingOption:(BUYOptionSelectionViewController *)controller;
- (void)optionSelectionControllerDidBackOutOfChoosingOption:(OptionSelectionViewController *)controller;
@end
/**
* The view controller containing a table view with variant options for selection
*/
@interface BUYOptionSelectionViewController : UITableViewController <BUYThemeable>
@interface OptionSelectionViewController : UITableViewController
/**
* Initalizer for the BUYOptionSelectionViewController
......@@ -92,6 +90,6 @@
/**
* Delegate to inform about option selections and cancellations
*/
@property (nonatomic, weak) id <BUYOptionSelectionDelegate> delegate;
@property (nonatomic, weak) id <OptionSelectionDelegate> delegate;
@end
//
// BUYOptionSelectionViewController.m
// OptionSelectionViewController.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,21 +24,19 @@
// THE SOFTWARE.
//
#import "BUYImageKit.h"
#import "BUYProduct+Options.h"
#import "BUYOptionSelectionViewController.h"
#import "BUYOptionValue.h"
#import "BUYOptionValueCell.h"
#import "BUYTheme.h"
#import "BUYTheme+Additions.h"
#import "ImageKit.h"
#import "OptionSelectionViewController.h"
#import "OptionValueCell.h"
#import "Theme+Additions.h"
@interface OptionSelectionViewController ()
@interface BUYOptionSelectionViewController ()
@property (nonatomic, strong) NSArray *optionValues;
@property (nonatomic, weak) BUYTheme *theme;
@property (nonatomic, strong) NSArray *filteredProductVariantsForSelectionOption;
@end
@implementation BUYOptionSelectionViewController
@implementation OptionSelectionViewController
- (instancetype)initWithOptionValues:(NSArray *)optionValues filteredProductVariantsForSelectionOption:(NSArray*)filteredProductVariantsForSelectionOption
{
......@@ -56,18 +54,10 @@
return self;
}
- (void)setTheme:(BUYTheme *)theme
{
_theme = theme;
self.view.backgroundColor = [theme backgroundColor];
self.tableView.backgroundColor = self.view.backgroundColor;
self.tableView.separatorColor = [theme separatorColor];
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView registerClass:[BUYOptionValueCell class] forCellReuseIdentifier:@"Cell"];
[self.tableView registerClass:[OptionValueCell class] forCellReuseIdentifier:@"Cell"];
self.tableView.tableFooterView = [UIView new];
}
......@@ -98,15 +88,15 @@
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
BUYOptionValue *optionValue = self.optionValues[indexPath.row];
BUYOptionValueCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
OptionValueCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
cell.selectedImageView.hidden = ![optionValue isEqual:self.selectedOptionValue];
if (self.isLastOption) {
cell.accessoryType = UITableViewCellAccessoryNone;
BUYProductVariant *productVariant = (BUYProductVariant*)self.filteredProductVariantsForSelectionOption[indexPath.row];
[cell setOptionValue:optionValue productVariant:productVariant currencyFormatter:self.currencyFormatter theme:self.theme];
[cell setOptionValue:optionValue productVariant:productVariant currencyFormatter:self.currencyFormatter];
} else {
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
[cell setOptionValue:optionValue productVariant:nil currencyFormatter:nil theme:self.theme];
[cell setOptionValue:optionValue productVariant:nil currencyFormatter:nil];
}
[cell setNeedsLayout];
[cell layoutIfNeeded];
......
//
// BUYOptionValueCell.h
// OptionValueCell.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,14 +25,12 @@
//
@import UIKit;
@class BUYTheme;
@class BUYOptionValue;
@class BUYProductVariant;
@import Buy;
/**
* A table view cell displaying the option value
*/
@interface BUYOptionValueCell : UITableViewCell
@interface OptionValueCell : UITableViewCell
/**
* Image view containing a checkmark for current option value selection
......@@ -45,9 +43,10 @@
* @param optionValue The option value to display
* @param productVariant The product variant matching the option value
* @param currencyFormatter A formatter with the shop's currency
* @param theme The current theme
*/
- (void)setOptionValue:(BUYOptionValue *)optionValue productVariant:(BUYProductVariant*)productVariant currencyFormatter:(NSNumberFormatter*)currencyFormatter theme:(BUYTheme *)theme;
- (void)setOptionValue:(BUYOptionValue *)optionValue productVariant:(BUYProductVariant*)productVariant currencyFormatter:(NSNumberFormatter*)currencyFormatter;
- (void)setSelectedBackgroundViewBackgroundColor:(UIColor *)selectedBackgroundViewBackgroundColor UI_APPEARANCE_SELECTOR;
@end
//
// BUYOptionValueCell.m
// OptionValueCell.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,24 +24,24 @@
// THE SOFTWARE.
//
#import "BUYOptionValueCell.h"
#import "BUYImageKit.h"
#import "BUYOptionValue.h"
#import "BUYProductVariant.h"
#import "BUYTheme.h"
#import "BUYTheme+Additions.h"
#import "DisclosureIndicatorView.h"
#import "ImageKit.h"
#import "OptionValueCell.h"
#import "Theme+Additions.h"
@interface OptionValueCell()
@interface BUYOptionValueCell()
@property (nonatomic, strong) NSArray *priceConstraints;
@property (nonatomic, strong) NSArray *noPriceConstraints;
@property (nonatomic, strong) NSArray *disclosureConstraints;
@property (nonatomic, strong) NSArray *noDisclosureConstraints;
@property (nonatomic, strong) UIImageView *disclosureIndicatorImageView;
@property (nonatomic, strong) DisclosureIndicatorView *disclosureIndicatorImageView;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UILabel *priceLabel;
@end
@implementation BUYOptionValueCell
@implementation OptionValueCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
......@@ -50,7 +50,6 @@
UIView *backgroundView = [[UIView alloc] init];
[self setSelectedBackgroundView:backgroundView];
self.textLabel.backgroundColor = [UIColor clearColor];
self.layoutMargins = UIEdgeInsetsMake(kBuyPaddingLarge, kBuyPaddingExtraLarge, kBuyPaddingLarge, kBuyPaddingLarge);
UIView *labelContainerView = [[UIView alloc] init];
......@@ -60,15 +59,15 @@
_titleLabel = [[UILabel alloc] init];
_titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
[_titleLabel setFont:[BUYTheme variantOptionValueFont]];
[_titleLabel setFont:[Theme variantOptionValueFont]];
[labelContainerView addSubview:_titleLabel];
_priceLabel = [[UILabel alloc] init];
_priceLabel.translatesAutoresizingMaskIntoConstraints = NO;
[_priceLabel setFont:[BUYTheme variantOptionPriceFont]];
[_priceLabel setFont:[Theme variantOptionPriceFont]];
[labelContainerView addSubview:_priceLabel];
UIImage *selectedImage = [BUYImageKit imageOfPreviousSelectionIndicatorImageWithFrame:CGRectMake(0, 0, 20, 20)];
UIImage *selectedImage = [ImageKit imageOfPreviousSelectionIndicatorImageWithFrame:CGRectMake(0, 0, 20, 20)];
selectedImage = [selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
_selectedImageView = [[UIImageView alloc] initWithImage:selectedImage];
......@@ -77,7 +76,7 @@
[_selectedImageView setContentHuggingPriority:UILayoutPriorityFittingSizeLevel forAxis:UILayoutConstraintAxisHorizontal];
[self.contentView addSubview:_selectedImageView];
_disclosureIndicatorImageView = [[UIImageView alloc] init];
_disclosureIndicatorImageView = [[DisclosureIndicatorView alloc] init];
_disclosureIndicatorImageView.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:_disclosureIndicatorImageView];
......@@ -127,23 +126,28 @@
}
}
- (void)setOptionValue:(BUYOptionValue *)optionValue productVariant:(BUYProductVariant*)productVariant currencyFormatter:(NSNumberFormatter*)currencyFormatter theme:(BUYTheme *)theme
-(void)tintColorDidChange
{
[super tintColorDidChange];
self.titleLabel.textColor = self.tintColor;
}
- (void)setSelectedBackgroundViewBackgroundColor:(UIColor *)selectedBackgroundViewBackgroundColor
{
self.selectedBackgroundView.backgroundColor = selectedBackgroundViewBackgroundColor;
}
- (void)setOptionValue:(BUYOptionValue *)optionValue productVariant:(BUYProductVariant*)productVariant currencyFormatter:(NSNumberFormatter*)currencyFormatter
{
self.titleLabel.textColor = theme.tintColor;
self.selectedImageView.tintColor = theme.tintColor;
self.backgroundColor = [theme backgroundColor];
self.selectedBackgroundView.backgroundColor = [theme selectedBackgroundColor];
self.disclosureIndicatorImageView.image = [BUYImageKit imageOfDisclosureIndicatorImageWithFrame:CGRectMake(0, 0, 10, 16) color:[theme disclosureIndicatorColor]];
self.titleLabel.text = optionValue.value;
if (productVariant) {
if (productVariant.available) {
self.priceLabel.text = [currencyFormatter stringFromNumber:productVariant.price];
self.priceLabel.textColor = [BUYTheme variantPriceTextColor];
self.priceLabel.textColor = [Theme variantPriceTextColor];
} else {
self.priceLabel.text = @"Sold Out";
self.priceLabel.textColor = [BUYTheme variantSoldOutTextColor];
self.priceLabel.text = NSLocalizedString(@"Sold Out", @"Sold out string displayed on option selector");
self.priceLabel.textColor = [Theme variantSoldOutTextColor];
}
[NSLayoutConstraint activateConstraints:self.priceConstraints];
[NSLayoutConstraint deactivateConstraints:self.noPriceConstraints];
......
//
// BUYVariantOptionView.h
// VariantOptionView.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -26,13 +26,11 @@
@import UIKit;
@class BUYOptionValue;
#import "BUYTheme.h"
#import "BUYTheme+Additions.h"
/**
* A view that contains a variant option name and option value for use to display the selected product variant
*/
@interface BUYVariantOptionView : UIView <BUYThemeable>
@interface VariantOptionView : UIView
/**
* Sets the text on the labels for the option value
......@@ -41,4 +39,6 @@
*/
- (void)setTextForOptionValue:(BUYOptionValue*)optionValue;
- (void)setOptionNameTextColor:(UIColor*)color UI_APPEARANCE_SELECTOR;
@end
//
// BUYVariantOptionView.m
// VariantOptionView.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,18 +24,21 @@
// THE SOFTWARE.
//
#import "BUYVariantOptionView.h"
#import "BUYOptionValue.h"
#import "UIFont+BUYAdditions.h"
@import UIKit;
@import Buy;
@interface BUYVariantOptionView ()
#import "Theme+Additions.h"
#import "VariantOptionView.h"
#import "UIFont+Additions.h"
@interface VariantOptionView ()
@property (nonatomic, strong) UILabel *optionNameLabel;
@property (nonatomic, strong) UILabel *optionValueLabel;
@end
@implementation BUYVariantOptionView
@implementation VariantOptionView
- (instancetype)initWithFrame:(CGRect)frame
{
......@@ -47,7 +50,7 @@
_optionNameLabel = [[UILabel alloc] init];
_optionNameLabel.textColor = [UIColor colorWithWhite:0.6f alpha:1];
_optionNameLabel.translatesAutoresizingMaskIntoConstraints = NO;
[_optionNameLabel setFont:[BUYTheme variantOptionNameFont]];
[_optionNameLabel setFont:[Theme variantOptionNameFont]];
[self addSubview:_optionNameLabel];
// Configure option value label
......@@ -55,7 +58,7 @@
_optionValueLabel.textColor = self.tintColor;
_optionValueLabel.translatesAutoresizingMaskIntoConstraints = NO;
[_optionValueLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
[_optionValueLabel setFont:[BUYTheme variantOptionValueFont]];
[_optionValueLabel setFont:[Theme variantOptionValueFont]];
[self addSubview:_optionValueLabel];
NSDictionary *views = NSDictionaryOfVariableBindings(_optionNameLabel, _optionValueLabel);
......@@ -82,12 +85,16 @@
self.optionValueLabel.textColor = self.tintColor;
}
- (void)setTheme:(BUYTheme *)theme
- (void)setBackgroundColor:(UIColor *)backgroundColor
{
self.optionNameLabel.textColor = [theme variantOptionNameTextColor];
self.backgroundColor = [theme backgroundColor];
[super setBackgroundColor:backgroundColor];
self.optionNameLabel.backgroundColor = self.backgroundColor;
self.optionValueLabel.backgroundColor = self.backgroundColor;
}
- (void)setOptionNameTextColor:(UIColor*)color
{
self.optionNameLabel.textColor = color;
}
@end
//
// PresentationController.h
// VariantSelectionPresentationController.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -29,7 +29,7 @@
/**
* A presentation controller containing the view controllers for variant selection
*/
@interface BUYPresentationControllerForVariantSelection : UIPresentationController
@interface VariantSelectionPresentationController : UIPresentationController
/**
* Blurred effects view that surrounds the variant selection navigation controller
......
//
// BUYPresentationController.m
// VariantSelectionPresentationController.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,9 +24,9 @@
// THE SOFTWARE.
//
#import "BUYPresentationControllerForVariantSelection.h"
#import "VariantSelectionPresentationController.h"
@implementation BUYPresentationControllerForVariantSelection
@implementation VariantSelectionPresentationController
- (instancetype)initWithPresentedViewController:(UIViewController *)presentedViewController presentingViewController:(UIViewController *)presentingViewController
{
......
//
// BUYVariantSelectionViewController.h
// VariantSelectionViewController.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,13 +25,11 @@
//
@import UIKit;
@import Buy;
@class BUYProduct;
@class BUYVariantSelectionViewController;
@class BUYProductVariant;
@class BUYTheme;
@class VariantSelectionViewController;
@protocol BUYVariantSelectionDelegate <NSObject>
@protocol VariantSelectionDelegate <NSObject>
/**
* Called when a user selects the last option for a product variant
......@@ -39,7 +37,7 @@
* @param controller The displayed variant selection view controller
* @param variant The selected product variant
*/
- (void)variantSelectionController:(BUYVariantSelectionViewController *)controller didSelectVariant:(BUYProductVariant *)variant;
- (void)variantSelectionController:(VariantSelectionViewController *)controller didSelectVariant:(BUYProductVariant *)variant;
/**
* Called when a user cancels out of the flow
......@@ -47,24 +45,23 @@
* @param controller The displayed variant selection view controller
* @param optionIndex The index matching the option value when the user cancelled selection in the flow
*/
- (void)variantSelectionControllerDidCancelVariantSelection:(BUYVariantSelectionViewController *)controller atOptionIndex:(NSUInteger)optionIndex;
- (void)variantSelectionControllerDidCancelVariantSelection:(VariantSelectionViewController *)controller atOptionIndex:(NSUInteger)optionIndex;
@end
/**
* The view controller that manages the option selection view controllers
*/
@interface BUYVariantSelectionViewController : UIViewController
@interface VariantSelectionViewController : UIViewController
/**
* Initalizer that takes a product and theme
* Initalizer that takes a product
*
* @param product The product to display variant options for selection
* @param theme The current theme
*
* @return An instance of BUYVariantSelectionViewController
*/
- (instancetype)initWithProduct:(BUYProduct *)product theme:(BUYTheme*)theme;
- (instancetype)initWithProduct:(BUYProduct *)product;
/**
* The product displaying variant option for
......@@ -84,6 +81,6 @@
/**
* The delegate that informs the product view of selection or cancellation
*/
@property (nonatomic, weak) id <BUYVariantSelectionDelegate> delegate;
@property (nonatomic, weak) id <VariantSelectionDelegate> delegate;
@end
//
// BUYVariantSelectionViewController.m
// VariantSelectionViewController.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,22 +24,16 @@
// THE SOFTWARE.
//
#import "BUYImageKit.h"
#import "BUYOptionSelectionNavigationController.h"
#import "BUYOptionSelectionViewController.h"
#import "BUYPresentationControllerForVariantSelection.h"
#import "BUYProduct+Options.h"
#import "BUYProductVariant+Options.h"
#import "BUYTheme.h"
#import "BUYTheme+Additions.h"
#import "BUYVariantSelectionViewController.h"
#import "BUYVariantOptionBreadCrumbsView.h"
#import "BUYOption.h"
#import "ImageKit.h"
#import "OptionSelectionNavigationController.h"
#import "OptionSelectionViewController.h"
#import "VariantSelectionPresentationController.h"
#import "VariantSelectionViewController.h"
#import "OptionBreadCrumbsView.h"
@interface BUYVariantSelectionViewController () <BUYOptionSelectionDelegate>
@interface VariantSelectionViewController () <OptionSelectionDelegate>
@property (nonatomic, strong) BUYProduct *product;
@property (nonatomic, weak) BUYTheme *theme;
@property (nonatomic, strong) NSMutableDictionary *selectedOptions;
@property (nonatomic, assign) BOOL changedOptionSelection;
@property (nonatomic, strong) NSArray *filteredProductVariantsForSelectionOption;
......@@ -47,9 +41,9 @@
@end
@implementation BUYVariantSelectionViewController
@implementation VariantSelectionViewController
- (instancetype)initWithProduct:(BUYProduct *)product theme:(BUYTheme*)theme
- (instancetype)initWithProduct:(BUYProduct *)product
{
NSParameterAssert(product);
......@@ -59,7 +53,6 @@
self.product = product;
self.selectedOptions = [NSMutableDictionary new];
self.optionValueNames = [NSMutableArray new];
self.theme = theme;
}
return self;
......@@ -69,23 +62,23 @@
{
[super viewDidLoad];
BUYOptionSelectionViewController *controller = [self nextOptionSelectionController];
OptionSelectionViewController *controller = [self nextOptionSelectionController];
// Add close button
UIImage *closeButton = [[BUYImageKit imageOfVariantCloseImageWithFrame:CGRectMake(0, 0, 18, 20)] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIImage *closeButton = [[ImageKit imageOfVariantCloseImageWithFrame:CGRectMake(0, 0, 18, 20)] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithImage:closeButton style:UIBarButtonItemStylePlain target:self action:@selector(dismissPopover)];
controller.navigationItem.leftBarButtonItem = barButtonItem;
[self.navigationController pushViewController:controller animated:NO];
BUYOptionSelectionNavigationController *navigationController = (BUYOptionSelectionNavigationController*)self.navigationController;
UIVisualEffectView *backgroundView = [(BUYPresentationControllerForVariantSelection*)navigationController.presentationController backgroundView];
OptionSelectionNavigationController *navigationController = (OptionSelectionNavigationController*)self.navigationController;
UIVisualEffectView *backgroundView = [(VariantSelectionPresentationController*)navigationController.presentationController backgroundView];
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissPopover)];
[backgroundView addGestureRecognizer:tapGestureRecognizer];
}
- (void)presentNextOption
{
BUYOptionSelectionViewController *controller = [self nextOptionSelectionController];
OptionSelectionViewController *controller = [self nextOptionSelectionController];
[self.navigationController pushViewController:controller animated:YES];
}
......@@ -106,37 +99,36 @@
return [[self.selectedOptions allKeys] count] == 1;
}
- (BUYOptionSelectionViewController *)nextOptionSelectionController
- (OptionSelectionViewController *)nextOptionSelectionController
{
NSUInteger index = [[self.selectedOptions allKeys] count];
BUYOption *option = self.product.options[index];
NSArray *options = [self.product valuesForOption:option variants:self.filteredProductVariantsForSelectionOption];
BUYOptionSelectionViewController *optionController = [[BUYOptionSelectionViewController alloc] initWithOptionValues:options filteredProductVariantsForSelectionOption:self.filteredProductVariantsForSelectionOption];
optionController.theme = self.theme;
OptionSelectionViewController *optionController = [[OptionSelectionViewController alloc] initWithOptionValues:options filteredProductVariantsForSelectionOption:self.filteredProductVariantsForSelectionOption];
optionController.delegate = self;
optionController.selectedOptionValue = self.changedOptionSelection ? nil : [self.selectedProductVariant optionValueForName:option.name];
optionController.isLastOption = [self isLastOption];
optionController.currencyFormatter = self.currencyFormatter;
optionController.title = option.name;
if (index > 0) {
[[(BUYOptionSelectionNavigationController*)self.navigationController breadsCrumbsView] setSelectedBuyOptionValues:[self.optionValueNames copy]];
optionController.tableView.contentInset = optionController.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(optionController.tableView.contentInset.top + CGRectGetHeight([[(BUYOptionSelectionNavigationController*)self.navigationController breadsCrumbsView] bounds]), optionController.tableView.contentInset.left, optionController.tableView.contentInset.bottom, optionController.tableView.contentInset.right);
[[(OptionSelectionNavigationController*)self.navigationController breadsCrumbsView] setSelectedBuyOptionValues:[self.optionValueNames copy]];
optionController.tableView.contentInset = optionController.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(optionController.tableView.contentInset.top + CGRectGetHeight([[(OptionSelectionNavigationController*)self.navigationController breadsCrumbsView] bounds]), optionController.tableView.contentInset.left, optionController.tableView.contentInset.bottom, optionController.tableView.contentInset.right);
}
return optionController;
}
- (void)dismissPopover
{
[(BUYOptionSelectionNavigationController*)self.navigationController setDismissWithCancelAnimation:YES];
[(OptionSelectionNavigationController*)self.navigationController setDismissWithCancelAnimation:YES];
if ([self.delegate respondsToSelector:@selector(variantSelectionControllerDidCancelVariantSelection:atOptionIndex:)]) {
[self.delegate variantSelectionControllerDidCancelVariantSelection:self atOptionIndex:self.selectedOptions.count];
}
}
#pragma mark - BUYOptionSelectionDelegate
#pragma mark - OptionSelectionDelegate
- (void)optionSelectionController:(BUYOptionSelectionViewController *)controller didSelectOptionValue:(BUYOptionValue *)optionValue
- (void)optionSelectionController:(OptionSelectionViewController *)controller didSelectOptionValue:(BUYOptionValue *)optionValue
{
self.changedOptionSelection |= ![controller.selectedOptionValue.value isEqualToString:optionValue.value];
self.selectedOptions[optionValue.name] = optionValue;
......@@ -155,13 +147,13 @@
}
}
- (void)optionSelectionControllerDidBackOutOfChoosingOption:(BUYOptionSelectionViewController *)controller
- (void)optionSelectionControllerDidBackOutOfChoosingOption:(OptionSelectionViewController *)controller
{
BUYOption *option = [controller.optionValues firstObject];
[self.selectedOptions removeObjectForKey:option.name];
[self.optionValueNames removeLastObject];
self.filteredProductVariantsForSelectionOption = controller.filteredProductVariantsForSelectionOption;
[[(BUYOptionSelectionNavigationController*)self.navigationController breadsCrumbsView] setSelectedBuyOptionValues:[self.optionValueNames copy]];
[[(OptionSelectionNavigationController*)self.navigationController breadsCrumbsView] setSelectedBuyOptionValues:[self.optionValueNames copy]];
}
- (NSArray*)filteredProductVariantsForSelectionOption
......
//
// NSString+Trim.h
// NavigationController.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,18 +24,14 @@
// THE SOFTWARE.
//
@import Foundation;
@import UIKit;
/**
* Convenience method for easier white space and newline character trimming
* A custom navigation controller used in the BUYProductViewController, adding a close button and the ability to theme the navigation bar
*/
@interface NSString (Trim)
@interface NavigationController : UINavigationController
/**
* Equivalent to `[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]`
*
* @return NSString without white space and newline characters
*/
- (NSString*)buy_trim;
@property (nonatomic) BOOL automaticallyMasksSeparator;
@end
//
// NavigationController.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 "NavigationController.h"
static CGFloat const kSeperatorVisibilityCurve = 0.01f;
static void *kObservationContext = &kObservationContext;
@interface NavigationController() <UINavigationBarDelegate>
@property (strong, nonatomic) UIView *separatorMask;
@property (readonly) UIScrollView *scrollView;
@end
@implementation NavigationController
- (instancetype)initWithRootViewController:(UIViewController *)rootViewController
{
self = [super initWithRootViewController:rootViewController];
if (self) {
UINavigationBar *navigationBar = self.navigationBar;
self.separatorMask = [UIView new];
self.separatorMask.backgroundColor = [UIColor whiteColor];
self.separatorMask.hidden = YES;
[navigationBar addSubview:self.separatorMask];
}
return self;
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
CGFloat height = 1.0f / [UIScreen mainScreen].scale;
UINavigationBar *navigationBar = self.navigationBar;
self.separatorMask.frame = CGRectMake(CGRectGetMinX(navigationBar.bounds), CGRectGetMaxY(navigationBar.bounds), CGRectGetWidth(navigationBar.bounds), height);
}
- (void)setAutomaticallyMasksSeparator:(BOOL)automaticallyMasksSeparator
{
self.separatorMask.hidden = !automaticallyMasksSeparator;
}
- (void)dealloc
{
[self.scrollView removeObserver:self forKeyPath:NSStringFromSelector(@selector(contentOffset))];
}
- (UIScrollView *)scrollView
{
UIView *view = [self.topViewController isViewLoaded] ? self.topViewController.view : nil;
if ([view isKindOfClass:[UIScrollView class]]) {
return (id)view;
} else {
return [view.subviews filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id _Nonnull evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
return [evaluatedObject isKindOfClass:[UIScrollView class]];
}]].firstObject;
}
}
- (CGFloat)seperatorAlphaWithOffset:(CGFloat)offset
{
CGFloat alpha = offset + CGRectGetMaxY(self.navigationBar.frame);
alpha *= kSeperatorVisibilityCurve;
return 1.0f - alpha;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
if (context == kObservationContext) {
UIScrollView *scrollView = object;
if (scrollView != self.scrollView) {
[scrollView removeObserver:self forKeyPath:keyPath];
} else {
CGFloat alpha = [self seperatorAlphaWithOffset:self.scrollView.contentOffset.y];
self.separatorMask.alpha = alpha;
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (void)updateObservedValues
{
if (!self.scrollView) {
return;
}
NSString *keyPath = NSStringFromSelector(@selector(contentOffset));
[self.scrollView addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:kObservationContext];
}
#pragma mark - UINavigationBarDelegate
- (void)navigationBar:(UINavigationBar *)navigationBar didPushItem:(UINavigationItem *)item
{
[self updateObservedValues];
}
- (void)navigationBar:(UINavigationBar *)navigationBar didPopItem:(UINavigationItem *)item
{
[self updateObservedValues];
}
@end
//
// PaymentViewController.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 AddressBook;
@import UIKit;
@import Buy;
#import "PaymentViewController.h"
@implementation PaymentViewController
@synthesize client = _client;
- (instancetype)initWithClient:(BUYClient *)client
{
self = [super init];
if (self) {
self.client = client;
}
return self;
}
- (BUYClient*)client
{
if (_client == nil) {
NSLog(@"`BUYClient` has not been initialized. Please initialize PaymentViewController with `initWithClient:` or set a `BUYClient` after Storyboard initialization");
}
return _client;
}
- (void)loadShopWithCallback:(void (^)(BOOL, NSError *))block
{
// Deprecated
}
- (BOOL)canShowApplePaySetup
{
return self.applePayPaymentProvider.canShowApplePaySetup;
}
- (BOOL)isApplePayAvailable
{
return self.applePayPaymentProvider.available;
}
- (BOOL)shouldShowApplePayButton {
return self.applePayPaymentProvider.available || [self canShowApplePaySetup];
}
- (BOOL)shouldShowApplePaySetup
{
return self.applePayPaymentProvider.available == NO && [self canShowApplePaySetup];
}
#pragma mark - Payment
- (void)startApplePayCheckout:(BUYCheckout *)checkout
{
[self.paymentController startCheckout:checkout withProviderType:BUYApplePayPaymentProviderId];
}
- (void)startWebCheckout:(BUYCheckout *)checkout
{
[self.paymentController startCheckout:checkout withProviderType:BUYWebPaymentProviderId];
}
- (BUYPaymentController *)paymentController
{
if (_paymentController == nil) {
_paymentController = [[BUYPaymentController alloc] init];
BUYWebCheckoutPaymentProvider *webPaymentProvider = [[BUYWebCheckoutPaymentProvider alloc] initWithClient:self.client];
webPaymentProvider.delegate = self;
[_paymentController addPaymentProvider:webPaymentProvider];
if (self.merchantId.length) {
BUYApplePayPaymentProvider *applePayPaymentProvider = [[BUYApplePayPaymentProvider alloc] initWithClient:self.client merchantID:self.merchantId];
applePayPaymentProvider.delegate = self;
[_paymentController addPaymentProvider:applePayPaymentProvider];
}
}
return _paymentController;
}
- (BUYWebCheckoutPaymentProvider *)webPaymentProvider
{
return (BUYWebCheckoutPaymentProvider*)[self.paymentController providerForType:BUYWebPaymentProviderId];
}
- (BUYApplePayPaymentProvider *)applePayPaymentProvider
{
return (BUYApplePayPaymentProvider*)[self.paymentController providerForType:BUYApplePayPaymentProviderId];
}
#pragma mark - Creating a Checkout using a Cart Token
- (void)startCheckoutWithCartToken:(NSString *)token
{
[self.client createCheckoutWithCartToken:token completion:^(BUYCheckout *checkout, NSError *error) {
[self handleCheckoutCompletion:checkout error:error];
}];
}
- (void)handleCheckoutCompletion:(BUYCheckout *)checkout error:(NSError *)error
{
if (checkout && error == nil) {
self.checkout = checkout;
[self.applePayPaymentProvider startCheckout:checkout];
}
else {
if ([self.delegate respondsToSelector:@selector(controller:failedToCreateCheckout:)]) {
[self.delegate controller:self failedToCreateCheckout:error];
}
}
}
- (void)checkoutCompleted:(BUYCheckout *)checkout status:(BUYStatus)status
{
if ([self.delegate respondsToSelector:@selector(controller:didCompleteCheckout:status:)]) {
[self.delegate controller:self didCompleteCheckout:checkout status:status];
}
}
#pragma mark - Payment delegate methods
+ (void)completeCheckoutFromLaunchURL:(NSURL *)url
{
[[NSNotificationCenter defaultCenter] postNotificationName:BUYSafariCallbackURLNotification object:nil userInfo:@{BUYURLKey: url}];
}
- (void)paymentProviderWillStartCheckout:(id<BUYPaymentProvider>)provider
{
if ([self.delegate respondsToSelector:@selector(controllerWillCheckoutViaWeb:)]) {
[self.delegate controllerWillCheckoutViaWeb:self];
}
}
- (void)paymentProviderDidDismissCheckout:(id<BUYPaymentProvider>)provider
{
if ([self.delegate respondsToSelector:@selector(controller:didDismissWebCheckout:)]) {
[self.delegate controller:self didDismissWebCheckout:self.checkout];
}
}
- (void)paymentProvider:(id<BUYPaymentProvider>)provider didFailCheckoutWithError:(NSError *)error
{
if ([self.delegate respondsToSelector:@selector(controller:failedToCreateCheckout:)]) {
[self.delegate controller:self failedToCreateCheckout:error];
}
}
- (void)paymentProvider:(id<BUYPaymentProvider>)provider didCompleteCheckout:(BUYCheckout *)checkout withStatus:(BUYStatus)status
{
if ([self.delegate respondsToSelector:@selector(controller:didCompleteCheckout:status:)]) {
[self.delegate controller:self didCompleteCheckout:checkout status:status];
}
}
- (void)paymentProvider:(id<BUYPaymentProvider>)provider wantsControllerPresented:(UIViewController *)controller
{
[self presentViewController:controller animated:YES completion:nil];
}
- (void)paymentProviderWantsControllerDismissed:(id<BUYPaymentProvider>)provider
{
[self dismissViewControllerAnimated:YES completion:nil];
}
-(PKPaymentRequest *)paymentRequest
{
return nil;
}
@end
......@@ -27,10 +27,6 @@
@import UIKit;
@import Buy;
#warning - Enter your merchant ID
// Adding a merchant ID will show Apple Pay in the BUYProductViewController (on supported devices)
#define MERCHANT_ID @""
@interface ProductListViewController : UITableViewController
- (instancetype)initWithClient:(BUYClient *)client collection:(BUYCollection*)collection;
......
......@@ -25,21 +25,29 @@
//
#import "ProductListViewController.h"
#import "ProductViewController.h"
#import "Theme.h"
#import "ShippingRatesTableViewController.h"
#import "ProductViewControllerToggleTableViewCell.h"
#import "ProductViewControllerThemeStyleTableViewCell.h"
#import "ProductViewControllerThemeTintColorTableViewCell.h"
#import <Buy/Buy.h>
//#warning - Enter your merchant ID
// Adding a merchant ID will show Apple Pay in the BUYProductViewController (on supported devices)
#define MERCHANT_ID @""
@interface ProductListViewController () <UIViewControllerPreviewingDelegate>
@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) BUYThemeStyle themeStyle;
@property (nonatomic, assign) ThemeStyle themeStyle;
@property (nonatomic, strong) NSArray *themeTintColors;
@property (nonatomic, assign) NSInteger themeTintColorSelectedIndex;
@property (nonatomic, assign) BOOL showsProductImageBackground;
......@@ -104,8 +112,8 @@
- (void)dealloc
{
[self.checkoutCreationTask cancel];
[self.collectionTask cancel];
[self.checkoutCreationOperation cancel];
[self.collectionOperation cancel];
}
- (void)presentCollectionSortOptions:(id)sender
......@@ -152,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 withTags:nil inCollection:self.collection.identifier sortOrder:collectionSort completion:^(NSArray *products, NSUInteger page, BOOL reachedEnd, NSError *error) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
if (error == nil && products) {
......@@ -271,14 +279,14 @@
- (void)demoNativeFlowWithProduct:(BUYProduct*)product
{
if (self.checkoutCreationTask.state == NSURLSessionTaskStateRunning) {
[self.checkoutCreationTask cancel];
if (self.checkoutCreationOperation.executing) {
[self.checkoutCreationOperation cancel];
}
BUYCart *cart = [[BUYCart alloc] init];
BUYCart *cart = [self.client.modelManager insertCartWithJSONDictionary:nil];
[cart addVariant:product.variants.firstObject];
BUYCheckout *checkout = [[BUYCheckout alloc] initWithCart:cart];
BUYCheckout *checkout = [[BUYCheckout alloc] initWithModelManager:cart.modelManager cart:cart];
// Apply billing and shipping address, as well as email to the checkout
checkout.shippingAddress = [self address];
......@@ -288,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) {
......@@ -304,7 +312,7 @@
- (void)demoProductViewControllerWithProduct:(BUYProduct*)product
{
BUYProductViewController *productViewController = [self productViewController];
ProductViewController *productViewController = [self productViewController];
[productViewController loadWithProduct:product completion:^(BOOL success, NSError *error) {
if (error == nil) {
if (self.presentViewController) {
......@@ -316,13 +324,13 @@
}];
}
-(BUYProductViewController*)productViewController
-(ProductViewController*)productViewController
{
BUYTheme *theme = [BUYTheme new];
Theme *theme = [Theme new];
theme.style = self.themeStyle;
theme.tintColor = self.themeTintColors[self.themeTintColorSelectedIndex];
theme.showsProductImageBackground = self.showsProductImageBackground;
BUYProductViewController *productViewController = [[BUYProductViewController alloc] initWithClient:self.client theme:theme];
ProductViewController *productViewController = [[ProductViewController alloc] initWithClient:self.client theme:theme];
productViewController.merchantId = MERCHANT_ID;
return productViewController;
}
......@@ -362,7 +370,7 @@
- (BUYAddress *)address
{
BUYAddress *address = [[BUYAddress alloc] init];
BUYAddress *address = [self.client.modelManager insertAddressWithJSONDictionary:nil];
address.address1 = @"150 Elgin Street";
address.address2 = @"8th Floor";
address.city = @"Ottawa";
......@@ -387,7 +395,7 @@
}
BUYProduct *product = self.products[indexPath.row];
BUYProductViewController *productViewController = [self productViewController];
ProductViewController *productViewController = [self productViewController];
[productViewController loadWithProduct:product completion:NULL];
previewingContext.sourceRect = cell.frame;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
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