Commit 5296345e by Brent Gulanowski Committed by Dima Bart

Move all product single views into Advanced Sample.

Also update for changes to how models are created, various other changes.
parent 53102c3a
//
// 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;
......
......@@ -27,13 +27,10 @@
#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 +84,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];
......@@ -292,7 +289,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]];
......
//
// 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
//
// BUYFont.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 "UIFont+BUYAdditions.h"
@implementation UIFont (BUYAdditions)
+ (UIFont *)preferredFontForTextStyle:(NSString *)style increasedPointSize:(CGFloat)size
{
UIFontDescriptor *descriptor = [UIFontDescriptor preferredFontDescriptorWithTextStyle:style];
return [UIFont fontWithDescriptor:descriptor size:descriptor.pointSize + size];
}
@end
//
// UIImage+BUYAdditions.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>
@interface UIImage (BUYAdditions)
+ (UIImage *)templateButtonBackgroundImage;
+ (UIImage *)templateImageWithFill:(UIColor *)fill stroke:(UIColor *)stroke edgeInsets:(UIEdgeInsets)edgeInsets;
@end
//
// UIImage+Additions.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 "UIImage+BUYAdditions.h"
static const CGFloat kDefaultCornerRadius = 4.0f;
static const CGFloat kDefaultStrokWidth = 1.0f;
@implementation UIImage (BUYAdditions)
+ (UIImage *)templateButtonBackgroundImage
{
UIImage *image = [UIImage templateImageWithFill:[UIColor blackColor] stroke:nil];
image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
return image;
}
+ (UIImage *)templateImageWithFill:(UIEdgeInsets)edgeInsets
{
UIImage *image = [UIImage templateImageWithFill:[UIColor blackColor] stroke:nil edgeInsets:edgeInsets];
image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
return image;
}
+ (UIImage *)templateImageWithFill:(UIColor *)fill stroke:(UIColor *)stroke
{
CGFloat defaultInsetAmount = kDefaultCornerRadius + 1.0f;
return [UIImage templateImageWithFill:fill stroke:stroke edgeInsets:UIEdgeInsetsMake(defaultInsetAmount, defaultInsetAmount, defaultInsetAmount, defaultInsetAmount)];
}
+ (UIImage *)templateImageWithFill:(UIColor *)fill stroke:(UIColor *)stroke edgeInsets:(UIEdgeInsets)edgeInsets
{
CGFloat defaultStrokeWidth = kDefaultStrokWidth;
return [self templateImageWithFill:fill stroke:stroke edgeInsets:edgeInsets strokeWidth:defaultStrokeWidth];
}
+ (UIImage *)templateImageWithFill:(UIColor *)fill stroke:(UIColor *)stroke edgeInsets:(UIEdgeInsets)edgeInsets strokeWidth:(CGFloat)width
{
CGRect rect = CGRectMake(0.0f, 0.0f,
edgeInsets.left + edgeInsets.right,
edgeInsets.top + edgeInsets.bottom);
CGFloat strokeOffset = stroke ? kDefaultStrokWidth * 0.5f : 0.0f;
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(rect, strokeOffset, strokeOffset) cornerRadius:edgeInsets.top];
path.lineWidth = width;
CGRect contextRect = CGRectOffset(rect, kDefaultStrokWidth * 0.5f, kDefaultStrokWidth * 0.5f);
UIGraphicsBeginImageContextWithOptions(contextRect.size, NO, 0);
if (fill) {
[fill setFill];
[path fill];
}
if (stroke) {
[stroke setStroke];
[path stroke];
}
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
image = [image resizableImageWithCapInsets:edgeInsets resizingMode:UIImageResizingModeStretch];
return image;
}
@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