Commit d956de37 by Dima Bart

Merge pull request #157 from Shopify/task/ui-migration

Migrate view classes from framework to advanced sample app
parents 53102c3a 5c64de6e
//
// 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 "Theme+Additions.h"
#import "UIFont+BUYAdditions.h"
#import "UIColor+BUYAdditions.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+BUYAdditions.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
//
// VisualEffectView.h
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
@import UIKit;
@interface VisualEffectView : UIVisualEffectView
- (void)setBlurEffectStyle:(UIBlurEffectStyle)blurEffectStyle UI_APPEARANCE_SELECTOR;
@end
//
// VisualEffectView.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 "VisualEffectView.h"
@implementation VisualEffectView
- (void)setBlurEffectStyle:(UIBlurEffectStyle)blurEffectStyle
{
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="10116" systemVersion="15E65" 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="10085"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9049"/>
</dependencies>
<scenes>
<!--Master-->
......@@ -11,6 +11,7 @@
<navigationController title="Master" id="rS3-R9-Ivy" sceneMemberID="viewController">
<navigationBar key="navigationBar" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" id="yXu-0R-QUA">
<autoresizingMask key="autoresizingMask"/>
<animations/>
</navigationBar>
<connections>
<segue destination="pGg-6v-bdr" kind="relationship" relationship="rootViewController" id="RxB-wf-QIq"/>
......@@ -27,6 +28,7 @@
<tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="mLL-gJ-YKr">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<animations/>
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="calibratedRGB"/>
<sections/>
<connections>
......
......@@ -25,8 +25,9 @@
//
@import UIKit;
@class BUYCheckout;
@class BUYClient;
@import Buy;
@import PassKit;
@import SafariServices;
extern NSString * const CheckoutCallbackNotification;
......
......@@ -24,16 +24,14 @@
// THE SOFTWARE.
//
#import <Buy/Buy.h>
#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>
......@@ -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,11 +137,11 @@ 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) {
[self.client storeCreditCard:[self creditCard] checkout:self.checkout completion:^(BUYCheckout *checkout, id<BUYPaymentToken> token, NSError *error) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
......@@ -156,7 +154,7 @@ NSString * const CheckoutCallbackNotification = @"CheckoutCallbackNotification";
NSLog(@"Error applying credit card: %@", error);
}
callback(error == nil && checkout);
callback(error == nil && checkout, token);
}];
}
......@@ -212,14 +210,14 @@ NSString * const CheckoutCallbackNotification = @"CheckoutCallbackNotification";
__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 completeCheckout:welf.checkout paymentToken:token completion:^(BUYCheckout *checkout, NSError *error) {
if (error == nil && checkout) {
......@@ -292,7 +290,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]];
......
//
// BUYPaymentButton.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, BUYPaymentButtonStyle) {
BUYPaymentButtonStyleWhite = 0,
BUYPaymentButtonStyleWhiteOutline,
BUYPaymentButtonStyleBlack
};
typedef NS_ENUM(NSInteger, BUYPaymentButtonType) {
BUYPaymentButtonTypePlain = 0,
BUYPaymentButtonTypeBuy,
BUYPaymentButtonTypeSetup NS_ENUM_AVAILABLE_IOS(9_0)
};
@interface BUYPaymentButton : UIButton
+ (instancetype)buttonWithType:(BUYPaymentButtonType)buttonType style:(BUYPaymentButtonStyle)buttonStyle;
@end
//
// ImageKit.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 Foundation;
@import UIKit;
/**
* Image generator for a variety of images using the BUYProductViewController.
*/
@interface ImageKit : NSObject
/**
* Generates a close button image for the variant selection navigation bar.
*
* @param frame The frame size of the image
*
* @return A close button image
*/
+ (UIImage*)imageOfVariantCloseImageWithFrame: (CGRect)frame;
/**
* Generates a checkmark image for use of displaying the previously selected variant
*
* @param frame The frame size of the image
*
* @return A checkmark for the previous variant selection
*/
+ (UIImage*)imageOfPreviousSelectionIndicatorImageWithFrame: (CGRect)frame;
/**
* Generates a custom disclosure indicator image
*
* @param frame The frame size of the image
* @param color The color for the disclosure indicator
*
* @return A disclusore indicator image
*/
+ (UIImage*)imageOfDisclosureIndicatorImageWithFrame: (CGRect)frame color:(UIColor*)color;
/**
* Generates a close button image for the product view's navigation bar
*
* @param frame The frame size of the image
* @param color The color for the close button image
* @param hasShadow True if the X should have a drop shadow
*
* @return A close button image
*/
+ (UIImage*)imageOfProductViewCloseImageWithFrame: (CGRect)frame color:(UIColor*)color hasShadow:(BOOL)hasShadow;
/**
* Generates a custom back button image for the variant selection navigation bar
*
* @param frame The frame size of the image
*
* @return A custom back button image
*/
+ (UIImage*)imageOfVariantBackImageWithFrame: (CGRect)frame;
@end
//
// 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+BUYAdditions.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
//
// UIImage+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/UIKit.h>
#import "UIButton+PaymentButton.h"
@interface UIImage (PaymentButton)
+ (UIImage *)paymentButtonImageWithFrame:(CGRect)originalFrame style:(PaymentButtonStyle)style type:(PaymentButtonType)type;
@end
......@@ -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];
......
//
// 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
//
// BUYProductViewFooter.h
// CheckoutButton.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,49 +25,31 @@
//
@import UIKit;
@class BUYProductVariant;
@class BUYTheme;
#import "BUYPaymentButton.h"
#import "BUYCheckoutButton.h"
@interface BUYProductViewFooter : UIView
/**
* A footer view for the BUYProductView that includes a checkout button and an Apple Pay button (if available)
*
* @param theme The theme for the footer view
* @param showApplePaySetup Show Apple Pay button with 'Set Up Apple Pay' text as determined by the presenter
*
* @return A footer view with a checkout and Apple Pay button
* A themed UIButton that includes a UIActivityIndicator
*/
- (instancetype)initWithTheme:(BUYTheme *)theme showApplePaySetup:(BOOL)showApplePaySetup;
@interface CheckoutButton : UIButton
/**
* A checkout button themed with the BUYTheme tintColor.
* This button is used for web checkout
*/
@property (nonatomic, strong) BUYCheckoutButton *checkoutButton;
/**
* An Apple Pay button, shown if Apple Pay is enabled and available on the device.
* The BUYPaymentButton is a PKPaymentButton on iOS 8.3 and greater.
* Styled to match the given theme.
* Creates a checkout button with UIButtonTypeSystem which inherits its color from the superview's tintColor
*
* @return A CheckoutButton with UIButtonTypeSystem
*/
@property (nonatomic, strong) BUYPaymentButton *buyPaymentButton;
+(instancetype)checkoutButton;
/**
* Sets the Apple Pay visible (or hides it). This updates the layout for the buttons.
* Show a UIActivityIndicator in place of text while loading
*
* @param isApplePayAvailable True when the Apple Pay button is visible
* @param show Show or hide the UIActivityIndicator
*/
- (void)setApplePayButtonVisible:(BOOL)isApplePayAvailable;
- (void)showActivityIndicator:(BOOL)show;
/**
* Lowers the alpha and disable the buttons if the `available` property on the
* BUYProductVariant is false.
* Sets the button text color
*
* @param productVariant The selected product variant that determines availability and functionality of the buttons.
* @param color The color for the button
*/
- (void)updateButtonsForProductVariant:(BUYProductVariant *)productVariant;
- (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+BUYAdditions.h"
#import "UIImage+BUYAdditions.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];
}
}
......
//
// DisclosureIndicatorView.h
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
@import UIKit;
@interface 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,24 +25,14 @@
//
@import UIKit;
@class BUYImageView;
@class BUYTheme;
@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
......
//
// 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 "BUYImageLink.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];
......@@ -88,8 +86,7 @@
- (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 "ProductHeaderCell.h"
#import "UIFont+BUYAdditions.h"
#import "BUYTheme+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.boolValue && 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.allObjects;
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 BUYImageLink;
@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 "BUYImageLink.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) {
......@@ -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,11 +39,21 @@
* use `initWithClient:`
*
* @param client A BUYClient configured to your shop
* @param theme A BUYTheme
* @param theme A Theme
*
* @return A PaymentViewController
*/
- (instancetype)initWithClient:(BUYClient *)client theme:(Theme *)theme;
/**
* 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
*
* @return A BUYViewController
* @return A PaymentViewController with an "Add to cart" button
*/
- (instancetype)initWithClient:(BUYClient *)client theme:(BUYTheme *)theme;
- (instancetype)initWithClient:(BUYClient *)client cart:(BUYCart *)cart;
/**
* Loads the product details
......
//
// 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 "BUYImageLink.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;
......
//
// 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,20 +24,19 @@
// THE SOFTWARE.
//
#import "BUYImageKit.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
{
......@@ -55,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];
}
......@@ -97,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 UIKit;
@import Buy;
#import "Theme+Additions.h"
#import "VariantOptionView.h"
#import "UIFont+BUYAdditions.h"
@interface BUYVariantOptionView ()
@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,23 +24,16 @@
// THE SOFTWARE.
//
#import "BUYImageKit.h"
#import "BUYOptionSelectionNavigationController.h"
#import "BUYOptionSelectionViewController.h"
#import "BUYPresentationControllerForVariantSelection.h"
#import "BUYProduct.h"
#import "BUYProductVariant.h"
#import "BUYTheme.h"
#import "BUYTheme+Additions.h"
#import "BUYVariantSelectionViewController.h"
#import "BUYVariantOptionBreadCrumbsView.h"
#import "BUYOption.h"
#import "BUYOptionValue.h"
@interface BUYVariantSelectionViewController () <BUYOptionSelectionDelegate>
#import "ImageKit.h"
#import "OptionSelectionNavigationController.h"
#import "OptionSelectionViewController.h"
#import "VariantSelectionPresentationController.h"
#import "VariantSelectionViewController.h"
#import "OptionBreadCrumbsView.h"
@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;
......@@ -48,9 +41,9 @@
@end
@implementation BUYVariantSelectionViewController
@implementation VariantSelectionViewController
- (instancetype)initWithProduct:(BUYProduct *)product theme:(BUYTheme*)theme
- (instancetype)initWithProduct:(BUYProduct *)product
{
NSParameterAssert(product);
......@@ -60,7 +53,6 @@
self.product = product;
self.selectedOptions = [NSMutableDictionary new];
self.optionValueNames = [NSMutableArray new];
self.theme = theme;
}
return self;
......@@ -70,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];
}
......@@ -107,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;
......@@ -156,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
......
//
// BUYCheckoutButton.h
// NavigationController.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,18 +25,13 @@
//
@import UIKit;
#import "BUYTheme.h"
/**
* A themed UIButton that includes a UIActivityIndicator
* A custom navigation controller used in the BUYProductViewController, adding a close button and the ability to theme the navigation bar
*/
@interface BUYCheckoutButton : UIButton <BUYThemeable>
@interface NavigationController : UINavigationController
/**
* Show a UIActivityIndicator in place of text while loading
*
* @param show Show or hide the UIActivityIndicator
*/
- (void)showActivityIndicator:(BOOL)show;
@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.view;
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
//
// BUYViewController.h
// PaymentViewController.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -26,69 +26,69 @@
@import UIKit;
@import PassKit;
#import "BUYClient.h"
#import "BUYCart.h"
#import "BUYCheckout.h"
@import Buy;
@class BUYViewController;
@class BUYCheckout;
@class BUYPaymentController;
@class PaymentViewController;
@protocol BUYViewControllerDelegate <NSObject>
@protocol PaymentViewControllerDelegate <NSObject>
@optional
// Look into having this protocol inherit from a generic one
/**
* This is called if there is an error in creating the BUYCheckout. These problems include not being connected to the Internet,
* or if there is a validation error in the checkout.
*
* @param controller The BUYViewController
* @param controller The PaymentViewController
* @param error An NSError describing the failure
*/
- (void)controller:(BUYViewController *)controller failedToCreateCheckout:(NSError *)error;
- (void)controller:(PaymentViewController *)controller failedToCreateCheckout:(NSError *)error;
/**
* This failure occurs when either the application is not properly configured to handle Apple Pay,
* or if the user does not have any credit cards configured in PassBook or cannot add any credit cards.
*
* @param controller The BUYViewController
* @param controller The PaymentViewController
*/
- (void)controllerFailedToStartApplePayProcess:(BUYViewController *)controller;
- (void)controllerFailedToStartApplePayProcess:(PaymentViewController *)controller;
/**
* This failure occurs whenever an update to BUYCheckout fails (shipping address, billing address, etc.)
*
* @param controller The BUYViewController
* @param controller The PaymentViewController
* @param checkout The BUYCheckout
* @param error An NSError describing the failure
*/
- (void)controller:(BUYViewController *)controller failedToUpdateCheckout:(BUYCheckout *)checkout withError:(NSError *)error;
- (void)controller:(PaymentViewController *)controller failedToUpdateCheckout:(BUYCheckout *)checkout withError:(NSError *)error;
/**
* This failure occurs when shipping rates cannot be retrieved.
*
* @param controller The BUYViewController
* @param controller The PaymentViewController
* @param checkout The BUYCheckout
* @param error An NSError describing the failure
*/
- (void)controller:(BUYViewController *)controller failedToGetShippingRates:(BUYCheckout *)checkout withError:(NSError *)error;
- (void)controller:(PaymentViewController *)controller failedToGetShippingRates:(BUYCheckout *)checkout withError:(NSError *)error;
/**
* This failure occurs whenever completing a checkout fails.
* This can occur if there is missing payment information or if the shop is improperly configured.
*
* @param controller The BUYViewController
* @param controller The PaymentViewController
* @param checkout The BUYCheckout
* @param error An NSError describing the failure
*/
- (void)controller:(BUYViewController *)controller failedToCompleteCheckout:(BUYCheckout *)checkout withError:(NSError *)error;
- (void)controller:(PaymentViewController *)controller failedToCompleteCheckout:(BUYCheckout *)checkout withError:(NSError *)error;
/**
* This is called whenever the checkout fully completes, success or failure.
*
* @param controller The BUYViewController
* @param controller The PaymentViewController
* @param checkout The BUYCheckout
* @param status Checkout status BUYStatus
*/
- (void)controller:(BUYViewController *)controller didCompleteCheckout:(BUYCheckout *)checkout status:(BUYStatus)status;
- (void)controller:(PaymentViewController *)controller didCompleteCheckout:(BUYCheckout *)checkout status:(BUYStatus)status;
/**
* This is called when the Apple Pay Authorization View Controller has been dismissed.
......@@ -98,25 +98,25 @@
* Note: If the PKPaymentAuthorizationStatus is not PKPaymentAuthorizationStatusSuccess we will expire the checkout by
* calling `expireCheckout:completion:` to release the hold on the product inventory.
*
* @param controller The BUYViewController
* @param controller The PaymentViewController
* @param checkout The BUYCheckout
*/
- (void)controller:(BUYViewController *)controller didDismissApplePayControllerWithStatus:(PKPaymentAuthorizationStatus)status forCheckout:(BUYCheckout *)checkout;
- (void)controller:(PaymentViewController *)controller didDismissApplePayControllerWithStatus:(PKPaymentAuthorizationStatus)status forCheckout:(BUYCheckout *)checkout;
/**
* This is called when the SFSafariViewController has been dismissed before checkout completion.
*
* @param controller The BUYViewController
* @param controller The PaymentViewController
* @param checkout The BUYCheckout
*/
- (void)controller:(BUYViewController *)controller didDismissWebCheckout:(BUYCheckout *)checkout;
- (void)controller:(PaymentViewController *)controller didDismissWebCheckout:(BUYCheckout *)checkout;
/**
* The view controller has been dismissed
*
* @param controller The BUYViewController
* @param controller The PaymentViewController
*/
- (void)didDismissViewController:(BUYViewController *)controller;
- (void)didDismissViewController:(PaymentViewController *)controller;
@optional
......@@ -125,26 +125,26 @@
*
* @param viewController the view controller
*/
- (void)controllerWillCheckoutViaWeb:(BUYViewController *)viewController;
- (void)controllerWillCheckoutViaWeb:(PaymentViewController *)viewController;
/**
* Called when the user chooses to checkout via Apple Pay
*
* @param viewController the view controller
*/
- (void)controllerWillCheckoutViaApplePay:(BUYViewController *)viewController;
- (void)controllerWillCheckoutViaApplePay:(PaymentViewController *)viewController;
@end
/**
* This base class guides you through the entire Apple Pay process.
*/
@interface BUYViewController : UIViewController <PKPaymentAuthorizationViewControllerDelegate>
@interface PaymentViewController : UIViewController <BUYPaymentProviderDelegate>
/**
* Register yourself as a BUYViewControllerDelegate to handle all errors, and status changes.
* Register yourself as a PaymentViewControllerDelegate to handle all errors, and status changes.
*/
@property (nonatomic, weak) id <BUYViewControllerDelegate> delegate;
@property (nonatomic, weak) id <PaymentViewControllerDelegate> delegate;
/**
* Set the BUYClient using the provided initializer method `initWithClient:` or
......@@ -203,14 +203,15 @@
/**
* The current checkout object
*/
@property (nonatomic, strong, readonly) BUYCheckout *checkout;
@property (nonatomic, strong) BUYCheckout *checkout;
/**
* Loads the shop details
*
* @param block callback block called on completion
*/
- (void)loadShopWithCallback:(void (^)(BOOL, NSError *))block;
- (void)loadShopWithCallback:(void (^)(BOOL, NSError *))block NS_DEPRECATED_IOS(8_0, 9_0);
#pragma mark - Apple Pay Overrides
......@@ -235,11 +236,11 @@
- (instancetype)init NS_UNAVAILABLE;
/**
* Creates a BUYViewController using your
* Creates a PaymentViewController using your
*
* @param client A BUYClient configured to your shop
*
* @return A BUYViewController
* @return A PaymentViewController
*/
- (instancetype)initWithClient:(BUYClient *)client;
......@@ -285,4 +286,6 @@
*/
+ (void)completeCheckoutFromLaunchURL:(NSURL *)url;
@property (nonatomic, strong) BUYPaymentController *paymentController;
@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,11 +25,19 @@
//
#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;
......@@ -39,7 +47,7 @@
@property (nonatomic, strong) NSURLSessionDataTask *checkoutCreationTask;
@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;
......@@ -275,7 +283,7 @@
[self.checkoutCreationTask cancel];
}
BUYCart *cart = [[BUYCart alloc] init];
BUYCart *cart = [self.client.modelManager insertCartWithJSONDictionary:nil];
[cart addVariant:product.variants.firstObject];
BUYCheckout *checkout = [[BUYCheckout alloc] initWithCart:cart];
......@@ -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;
......
//
// BUYStoreViewController.h
// UIColor+BUYAdditions.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,60 +25,35 @@
//
@import UIKit;
#import "BUYViewController.h"
#import "BUYError.h"
typedef NS_ENUM(NSUInteger, BUYCheckoutType){
BUYCheckoutTypeNormal,
BUYCheckoutTypeApplePay,
BUYCheckoutTypeCancel
};
#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]
typedef void (^BUYCheckoutTypeBlock)(BUYCheckoutType type);
@class BUYStoreViewController;
/**
* The BUYStoreViewControllerDelegate protocol implements methods related to the checkout process
*/
@protocol BUYStoreViewControllerDelegate <BUYViewControllerDelegate>
@interface UIColor (BUYAdditions)
/**
* Tells the delegate that the user has proceeded to checkout. Use this opportunity to present an interface to a
* user to choose between checking out with Apple Pay or standard webcheckout.
* Note: Before presenting an option for Apple Pay, check if the device is setup to do so by calling `[PKPaymentAuthorizationViewController canMakePayments]`
* Check if the color is light (brightness of colors combined less than .5)
* Supports RGB and grey space colors
*
* @param controller The controller with an embedded WKWebView displaying the Shopify store
* @param completionHandler (^BUYCheckoutTypeBlock)(BUYCheckoutType type);
* @return Returns true if the color is light
*/
- (void)controller:(BUYStoreViewController *)controller shouldProceedWithCheckoutType:(BUYCheckoutTypeBlock)completionHandler;
@end
- (BOOL)isLightColor;
/**
* This controller shows you how to build a controller that embeds a WKWebView (iOS 8+) with your store in it.
* This means that you can show off your store and its sleek responsive design without having to build a full native app to showcase it.
*/
@interface BUYStoreViewController : BUYViewController
/**
* Creates a view controller with an embedded webview to show the shops storefront
* Creates a UIColor from a hex value
*
* @param client The client configured to your shop
* @param url The address where the shop can be viewed
* @param hex the hex value to convert to a UIColor
*
* @return the BUYStoreViewController instance
*/
- (instancetype)initWithClient:(BUYClient *)client url:(NSURL *)url;
/**
* Jumps back to the shops home page
* @return A UIColor object
*/
- (void)reloadHomePage;
+ (UIColor*)colorWithHex:(NSInteger)hex;
+ (UIColor*)colorWithHexString:(NSString *)hexString;
/**
* The BUYStoreViewControllerDelegate
* Creates a string representing the hex value for the color
*
* @return String representing the hex value
*/
@property (nonatomic, weak) id <BUYStoreViewControllerDelegate> delegate;
- (NSString *)hexString;
@end
//
// UIColor+BUYAdditions.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 "UIColor+BUYAdditions.h"
@implementation UIColor (BUYAdditions)
-(BOOL)isLightColor
{
CGFloat colorBrightness = 0;
CGColorSpaceRef colorSpace = CGColorGetColorSpace(self.CGColor);
CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(colorSpace);
if (colorSpaceModel == kCGColorSpaceModelRGB) {
const CGFloat *componentColors = CGColorGetComponents(self.CGColor);
colorBrightness = ((componentColors[0] * 299) + (componentColors[1] * 587) + (componentColors[2] * 114)) / 1000;
} else {
[self getWhite:&colorBrightness alpha:0];
}
return (colorBrightness >= .5f);
}
+ (UIColor*)colorWithHex:(NSInteger)hex
{
return [UIColor colorWithRed:(((hex & 0xFF0000) >> 16)) / 255.0f
green:(((hex & 0x00FF00) >> 8)) / 255.0f
blue:(((hex & 0x0000FF) >> 0)) / 255.0f
alpha:1.0];
}
+ (UIColor*)colorWithHexString:(NSString *)hexString
{
if ([hexString length] == 0) {
return nil;
}
NSScanner *scanner = [NSScanner scannerWithString:hexString];
unsigned hex;
[scanner scanHexInt:&hex];
return [UIColor colorWithHex:hex];
}
- (NSString *)hexString
{
CGFloat r;
CGFloat g;
CGFloat b;
[self getRed:&r green:&g blue:&b alpha:nil];
return [NSString stringWithFormat:@"#%02lX%02lX%02lX",
lround(r * 255),
lround(g * 255),
lround(b * 255)];
}
@end
//
// BUYFont.h
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
@import UIKit;
@interface UIFont (BUYAdditions)
/**
* Class method to allow system fonts to have increased point sizes from the OS default.
*
* @param style The text style for the font.
* @param size A positive value to increase the default font's point size by.
*
* @return A system font with an optionally increased point size.
*/
+ (UIFont *)preferredFontForTextStyle:(NSString *)style increasedPointSize:(CGFloat)size;
@end
//
// BUYFontAdditionsTests.m
// BUYFont.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,27 +24,14 @@
// THE SOFTWARE.
//
#import <XCTest/XCTest.h>
#import "UIFont+BUYAdditions.h"
@interface BUYFontAdditionsTests : XCTestCase
@implementation UIFont (BUYAdditions)
@end
@implementation BUYFontAdditionsTests
- (void)testIncreasedFontSize
+ (UIFont *)preferredFontForTextStyle:(NSString *)style increasedPointSize:(CGFloat)size
{
static CGFloat const increase = 2.0;
UIFont *font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
CGFloat newSize = font.pointSize + increase;
NSMutableDictionary *attributes = [font.fontDescriptor.fontAttributes mutableCopy];
attributes[UIFontDescriptorSizeAttribute] = @(newSize);
UIFont *expected = [UIFont fontWithDescriptor:[UIFontDescriptor fontDescriptorWithFontAttributes:attributes] size:newSize];
UIFont *actual = [UIFont preferredFontForTextStyle:UIFontTextStyleBody increasedPointSize:increase];
XCTAssertEqualObjects(actual, expected);
UIFontDescriptor *descriptor = [UIFontDescriptor preferredFontDescriptorWithTextStyle:style];
return [UIFont fontWithDescriptor:descriptor size:descriptor.pointSize + size];
}
@end
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