diff --git a/Kickstarter-iOS/Locales/Base.lproj/Localizable.strings b/Kickstarter-iOS/Locales/Base.lproj/Localizable.strings index f1fbc6693d..519c80a535 100644 --- a/Kickstarter-iOS/Locales/Base.lproj/Localizable.strings +++ b/Kickstarter-iOS/Locales/Base.lproj/Localizable.strings @@ -169,6 +169,7 @@ "Find_projects_youll_love_in_art_design_film" = "Find projects you’ll love in art, design, film, games, music, and more. Once you back a project, you’ll see all your activity here."; "First_created" = "First created"; "Fix" = "Fix"; +"Fix_your_payment_method" = "Fix your payment method"; "Follow_friend_name" = "Follow %{friend_name}"; "Follow_friends" = "Follow friends"; "Follow_more_friends" = "Follow more friends"; @@ -275,6 +276,7 @@ "Newsletters" = "Newsletters"; "No_Results" = "No Results"; "No_comments_yet" = "No comments yet."; +"No_longer_available" = "No longer available"; "No_messages" = "No messages"; "No_nevermind" = "No, nevermind"; "No_one_has_posted_an_update_yet" = "No one has posted an update yet."; diff --git a/Kickstarter-iOS/Locales/de.lproj/Localizable.strings b/Kickstarter-iOS/Locales/de.lproj/Localizable.strings index 672e328402..5af0276d82 100644 --- a/Kickstarter-iOS/Locales/de.lproj/Localizable.strings +++ b/Kickstarter-iOS/Locales/de.lproj/Localizable.strings @@ -169,6 +169,7 @@ "Find_projects_youll_love_in_art_design_film" = "Finde Projekte nach deinem Geschmack - in Kunst, Design, Film, Spiele, Musik und vielen anderen Kategorien. Wenn du ein Projekt unterstützt hast, wird deren Aktivität hier angezeigt."; "First_created" = "Erstes Projekt"; "Fix" = "Korrigieren"; +"Fix_your_payment_method" = "Zahlungsmethode ändern"; "Follow_friend_name" = "%{friend_name} folgen."; "Follow_friends" = "Freunden folgen"; "Follow_more_friends" = "Folge noch mehr Freunden"; @@ -275,6 +276,7 @@ "Newsletters" = "Newsletter"; "No_Results" = "Keine Ergebnisse"; "No_comments_yet" = "Bisher noch keine Kommentare."; +"No_longer_available" = "Nicht mehr verfügbar"; "No_messages" = "Keine Nachrichten"; "No_nevermind" = "Nein, ich habe es mir anders überlegt"; "No_one_has_posted_an_update_yet" = "Es wurden noch keine Updates gepostet."; diff --git a/Kickstarter-iOS/Locales/es.lproj/Localizable.strings b/Kickstarter-iOS/Locales/es.lproj/Localizable.strings index d48a6d372c..5e1604b063 100644 --- a/Kickstarter-iOS/Locales/es.lproj/Localizable.strings +++ b/Kickstarter-iOS/Locales/es.lproj/Localizable.strings @@ -169,6 +169,7 @@ "Find_projects_youll_love_in_art_design_film" = "Proyectos a tu gusto - en arte, diseño, cine, juegos, música y otras categorías. Una vez que hayas patrocinado un proyecto, verás todas las actividades pertinentes aquí."; "First_created" = "Primer proyecto creado"; "Fix" = "Corregir"; +"Fix_your_payment_method" = "Corrige tu método de pago"; "Follow_friend_name" = "Seguir a %{friend_name}."; "Follow_friends" = "Seguir amigos"; "Follow_more_friends" = "Seguir a más amigos"; @@ -275,6 +276,7 @@ "Newsletters" = "Boletines informativos"; "No_Results" = "Sin resultados"; "No_comments_yet" = "No hay comentarios todavia."; +"No_longer_available" = "Ya no está disponible"; "No_messages" = "No hay mensajes"; "No_nevermind" = "No, ignorar"; "No_one_has_posted_an_update_yet" = "Todavía no se han publicado actualizaciones."; diff --git a/Kickstarter-iOS/Locales/fr.lproj/Localizable.strings b/Kickstarter-iOS/Locales/fr.lproj/Localizable.strings index 54655a5c9d..ce08422090 100644 --- a/Kickstarter-iOS/Locales/fr.lproj/Localizable.strings +++ b/Kickstarter-iOS/Locales/fr.lproj/Localizable.strings @@ -169,6 +169,7 @@ "Find_projects_youll_love_in_art_design_film" = "Découvrez des projets que vous allez adorer : art, design, cinéma, jeux, musique et plus encore. L'activité des projets que vous soutenez s'affichera ici."; "First_created" = "Premier projet créé"; "Fix" = "Corriger"; +"Fix_your_payment_method" = "Corriger votre moyen de paiement"; "Follow_friend_name" = "Suivre %{friend_name}"; "Follow_friends" = "Suivez vos amis"; "Follow_more_friends" = "Suivre plus d'amis"; @@ -275,6 +276,7 @@ "Newsletters" = "Lettres d'information"; "No_Results" = "Pas de résultats"; "No_comments_yet" = "Pas de commentaires."; +"No_longer_available" = "Indisponible"; "No_messages" = "Pas de messages"; "No_nevermind" = "Non, j'ai changé d'avis"; "No_one_has_posted_an_update_yet" = "Pas d'actus publiées pour le moment."; diff --git a/Kickstarter-iOS/Locales/ja.lproj/Localizable.strings b/Kickstarter-iOS/Locales/ja.lproj/Localizable.strings index 5d54642d32..f1bca1ec6f 100644 --- a/Kickstarter-iOS/Locales/ja.lproj/Localizable.strings +++ b/Kickstarter-iOS/Locales/ja.lproj/Localizable.strings @@ -169,6 +169,7 @@ "Find_projects_youll_love_in_art_design_film" = "お気に入りを見つけて、クリエイティブなプロジェクトに生命を吹き込もう。"; "First_created" = "1つめのプロジェクト"; "Fix" = "修正する"; +"Fix_your_payment_method" = "お支払い方法を修正"; "Follow_friend_name" = "%{friend_name} をフォロー"; "Follow_friends" = "友達をフォロー"; "Follow_more_friends" = "もっと友達をフォローする"; @@ -275,6 +276,7 @@ "Newsletters" = "ニュースレター"; "No_Results" = "該当結果なし"; "No_comments_yet" = "まだコメントはありません。"; +"No_longer_available" = "利用できなくなりました"; "No_messages" = "メッセージがありません。"; "No_nevermind" = "いいえ、削除しません"; "No_one_has_posted_an_update_yet" = "まだアップデートの投稿はありません。"; diff --git a/Kickstarter-iOS/Views/Controllers/BetaToolsViewController.swift b/Kickstarter-iOS/Views/Controllers/BetaToolsViewController.swift index 6ed4f64614..6343ccc85d 100644 --- a/Kickstarter-iOS/Views/Controllers/BetaToolsViewController.swift +++ b/Kickstarter-iOS/Views/Controllers/BetaToolsViewController.swift @@ -132,7 +132,7 @@ internal final class BetaToolsViewController: UITableViewController { self.navigationController?.dismiss(animated: true) } - // MARK: Private Helper Functions + // MARK: - Functions private func configureFooterView() { let containerView = UIView(frame: .zero) diff --git a/Kickstarter-iOS/Views/Controllers/DashboardProjectsDrawerViewController.swift b/Kickstarter-iOS/Views/Controllers/DashboardProjectsDrawerViewController.swift index fdbbc78181..64253da6d6 100644 --- a/Kickstarter-iOS/Views/Controllers/DashboardProjectsDrawerViewController.swift +++ b/Kickstarter-iOS/Views/Controllers/DashboardProjectsDrawerViewController.swift @@ -118,7 +118,8 @@ internal final class DashboardProjectsDrawerViewController: UITableViewControlle self.tableView.backgroundView?.addGestureRecognizer( UITapGestureRecognizer( target: self, action: #selector(DashboardProjectsDrawerViewController.backgroundTapped) - )) + ) + ) }) UIView.animate( diff --git a/Kickstarter-iOS/Views/Controllers/DeprecatedRewardPledgeViewController.swift b/Kickstarter-iOS/Views/Controllers/DeprecatedRewardPledgeViewController.swift index c35ed2e15b..3218a691e3 100644 --- a/Kickstarter-iOS/Views/Controllers/DeprecatedRewardPledgeViewController.swift +++ b/Kickstarter-iOS/Views/Controllers/DeprecatedRewardPledgeViewController.swift @@ -70,8 +70,7 @@ internal final class DeprecatedRewardPledgeViewController: UIViewController { project: Project, reward: Reward, applePayCapable: Bool = PKPaymentAuthorizationViewController.applePayCapable() - ) - -> DeprecatedRewardPledgeViewController { + ) -> DeprecatedRewardPledgeViewController { let vc = Storyboard.RewardPledge.instantiate(DeprecatedRewardPledgeViewController.self) vc.viewModel.inputs.configureWith(project: project, reward: reward, applePayCapable: applePayCapable) return vc diff --git a/Kickstarter-iOS/Views/Controllers/ProjectPamphletViewController.swift b/Kickstarter-iOS/Views/Controllers/ProjectPamphletViewController.swift index 811b19c606..d21f221448 100644 --- a/Kickstarter-iOS/Views/Controllers/ProjectPamphletViewController.swift +++ b/Kickstarter-iOS/Views/Controllers/ProjectPamphletViewController.swift @@ -86,7 +86,7 @@ public final class ProjectPamphletViewController: UIViewController { } private var initialTopConstraint: CGFloat { - return parent?.view.safeAreaInsets.top ?? 0.0 + return self.parent?.view.safeAreaInsets.top ?? 0.0 } private func configurePledgeCTAContainerView() { diff --git a/Kickstarter-iOS/Views/RewardCardContainerView.swift b/Kickstarter-iOS/Views/RewardCardContainerView.swift index 09bdc2bf4a..354dc5a387 100644 --- a/Kickstarter-iOS/Views/RewardCardContainerView.swift +++ b/Kickstarter-iOS/Views/RewardCardContainerView.swift @@ -27,6 +27,8 @@ public final class RewardCardContainerView: UIView { private let pledgeButtonLayoutGuide = UILayoutGuide() private var pledgeButtonMarginConstraints: [NSLayoutConstraint]? + private var pledgeButtonShownConstraints: [NSLayoutConstraint] = [] + private var pledgeButtonHiddenConstraints: [NSLayoutConstraint] = [] private let rewardCardView: RewardCardView = { RewardCardView(frame: .zero) |> \.translatesAutoresizingMaskIntoConstraints .~ false @@ -52,9 +54,6 @@ public final class RewardCardContainerView: UIView { |> roundedStyle(cornerRadius: Styles.grid(3)) |> \.layoutMargins .~ .init(all: Styles.grid(3)) - _ = self.pledgeButton - |> greenButtonStyle - _ = self.gradientView |> \.backgroundColor .~ .clear |> \.startPoint .~ .zero @@ -82,8 +81,29 @@ public final class RewardCardContainerView: UIView { .rewardCardView(self.rewardCardView, didTapWithRewardId: rewardId) } - self.pledgeButton.rac.title = self.viewModel.outputs.pledgeButtonTitleText + self.viewModel.outputs.pledgeButtonTitleText.observeValues { [weak self] text in + self?.pledgeButton.setTitle(text, for: .normal) + } self.pledgeButton.rac.enabled = self.viewModel.outputs.pledgeButtonEnabled + + self.viewModel.outputs.pledgeButtonHidden.observeValues { [weak self] hidden in + guard let self = self else { return } + + if hidden { + NSLayoutConstraint.activate(self.pledgeButtonHiddenConstraints) + NSLayoutConstraint.deactivate(self.pledgeButtonShownConstraints) + } else { + NSLayoutConstraint.activate(self.pledgeButtonShownConstraints) + NSLayoutConstraint.deactivate(self.pledgeButtonHiddenConstraints) + } + } + + self.viewModel.outputs.pledgeButtonStyleType + .observeForUI() + .observeValues { [weak self] styleType in + guard let self = self else { return } + _ = self.pledgeButton |> styleType.style + } } internal func configure(with value: (project: Project, reward: Either)) { @@ -112,6 +132,25 @@ public final class RewardCardContainerView: UIView { } public func setupConstraints() { + self.pledgeButtonHiddenConstraints = self.hiddenPledgeHiddenConstraints() + self.pledgeButtonShownConstraints = self.shownPledgeButtonConstraints() + NSLayoutConstraint.activate(self.pledgeButtonShownConstraints) + } + + private func hiddenPledgeHiddenConstraints() -> [NSLayoutConstraint] { + let containerMargins = self.layoutMarginsGuide + + let rewardCardViewConstraints = [ + self.rewardCardView.leftAnchor.constraint(equalTo: containerMargins.leftAnchor), + self.rewardCardView.rightAnchor.constraint(equalTo: containerMargins.rightAnchor), + self.rewardCardView.topAnchor.constraint(equalTo: containerMargins.topAnchor), + self.rewardCardView.bottomAnchor.constraint(equalTo: containerMargins.bottomAnchor) + ] + + return rewardCardViewConstraints + } + + private func shownPledgeButtonConstraints() -> [NSLayoutConstraint] { let containerMargins = self.layoutMarginsGuide let rewardCardViewConstraints = [ @@ -131,36 +170,46 @@ public final class RewardCardContainerView: UIView { self.pledgeButtonLayoutGuide.bottomAnchor.constraint(equalTo: containerMargins.bottomAnchor), self.pledgeButtonLayoutGuide.leftAnchor.constraint(equalTo: containerMargins.leftAnchor), self.pledgeButtonLayoutGuide.rightAnchor.constraint(equalTo: containerMargins.rightAnchor), - // swiftlint:disable:next line_length - self.pledgeButtonLayoutGuide.topAnchor.constraint(equalTo: self.rewardCardView.bottomAnchor, constant: Styles.grid(3)), + self.pledgeButtonLayoutGuide.topAnchor.constraint( + equalTo: self.rewardCardView.bottomAnchor, constant: Styles.grid(3) + ), self.pledgeButtonLayoutGuide.heightAnchor.constraint(equalTo: self.pledgeButton.heightAnchor) ] - NSLayoutConstraint.activate([ + let constraints = [ [pledgeButtonTopConstraint], rewardCardViewConstraints, pledgeButtonLayoutGuideConstraints ] - .flatMap { $0 }) + .flatMap { $0 } + + return constraints } private func addBottomViewsMarginConstraints(with layoutMarginsGuide: UILayoutGuide) { NSLayoutConstraint.deactivate(self.pledgeButtonMarginConstraints ?? []) let minTouchSize = Styles.minTouchSize.height - NSLayoutConstraint.activate([ + let pledgeButtonMarginConstraints = [ self.pledgeButton.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor), self.pledgeButton.rightAnchor.constraint(equalTo: layoutMarginsGuide.rightAnchor), self.pledgeButton.bottomAnchor.constraint(lessThanOrEqualTo: layoutMarginsGuide.bottomAnchor), - self.pledgeButton.heightAnchor.constraint(greaterThanOrEqualToConstant: minTouchSize) - ]) + self.pledgeButton.heightAnchor.constraint( + greaterThanOrEqualToConstant: minTouchSize + ) + ] + + NSLayoutConstraint.activate(pledgeButtonMarginConstraints) + + self.pledgeButtonMarginConstraints = pledgeButtonMarginConstraints NSLayoutConstraint.activate([ self.gradientView.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor), self.gradientView.rightAnchor.constraint(equalTo: layoutMarginsGuide.rightAnchor), self.gradientView.topAnchor.constraint(equalTo: self.pledgeButton.topAnchor, constant: -minTouchSize), - // swiftlint:disable:next line_length - self.gradientView.bottomAnchor.constraint(equalTo: self.pledgeButton.bottomAnchor, constant: minTouchSize / 2) + self.gradientView.bottomAnchor.constraint( + equalTo: self.pledgeButton.bottomAnchor, constant: minTouchSize / 2 + ) ]) } diff --git a/Kickstarter-iOS/Views/RewardCardContainerViewTests.swift b/Kickstarter-iOS/Views/RewardCardContainerViewTests.swift new file mode 100644 index 0000000000..7017e0c71d --- /dev/null +++ b/Kickstarter-iOS/Views/RewardCardContainerViewTests.swift @@ -0,0 +1,327 @@ +import Foundation +@testable import Kickstarter_Framework +@testable import KsApi +@testable import Library +import Prelude +import UIKit + +final class RewardCardContainerViewTests: TestCase { + override func setUp() { + super.setUp() + + AppEnvironment.pushEnvironment(mainBundle: Bundle.framework) + } + + func testLive_BackedProject_BackedReward() { + combos([Language.en], [Device.phone4_7inch], allRewards).forEach { language, device, rewardTuple in + withEnvironment(language: language) { + let (rewardDescription, reward) = rewardTuple + + let project = Project.cosmicSurgery + |> Project.lens.state .~ .live + |> Project.lens.personalization.isBacking .~ true + |> Project.lens.personalization.backing .~ ( + .template + |> Backing.lens.reward .~ reward + |> Backing.lens.rewardId .~ reward.id + |> Backing.lens.shippingAmount .~ 10 + |> Backing.lens.amount .~ 700 + ) + + let vc = rewardCardInViewController( + language: language, + device: device, + project: project, + reward: reward + ) + + FBSnapshotVerifyView(vc.view, identifier: "\(rewardDescription)_lang_\(language)_device_\(device)") + } + } + } + + func testLive_BackedProject_NonBackedReward() { + combos([Language.en], [Device.phone4_7inch], allRewards).forEach { language, device, rewardTuple in + withEnvironment(language: language) { + let (rewardDescription, reward) = rewardTuple + + let project = Project.cosmicSurgery + |> Project.lens.state .~ .live + |> Project.lens.personalization.isBacking .~ true + |> Project.lens.personalization.backing .~ ( + .template + |> Backing.lens.reward .~ Reward.otherReward + |> Backing.lens.rewardId .~ Reward.otherReward.id + |> Backing.lens.shippingAmount .~ 10 + |> Backing.lens.amount .~ 700 + ) + + let vc = rewardCardInViewController( + language: language, + device: device, + project: project, + reward: reward + ) + + FBSnapshotVerifyView(vc.view, identifier: "\(rewardDescription)_lang_\(language)_device_\(device)") + } + } + } + + func testLive_NonBackedProject_LoggedIn() { + combos([Language.en], [Device.phone4_7inch], allRewards).forEach { language, device, rewardTuple in + withEnvironment(language: language) { + let (rewardDescription, reward) = rewardTuple + + let project = Project.cosmicSurgery + |> Project.lens.state .~ .live + |> Project.lens.personalization.isBacking .~ false + |> Project.lens.personalization.backing .~ nil + + let vc = rewardCardInViewController( + language: language, + device: device, + project: project, + reward: reward + ) + + FBSnapshotVerifyView(vc.view, identifier: "\(rewardDescription)_lang_\(language)_device_\(device)") + } + } + } + + func testLive_NonBackedProject_LoggedOut() { + combos([Language.en], [Device.phone4_7inch], allRewards).forEach { language, device, rewardTuple in + withEnvironment(language: language) { + let (rewardDescription, reward) = rewardTuple + + let project = Project.cosmicSurgery + |> Project.lens.state .~ .live + |> Project.lens.personalization.isBacking .~ nil + |> Project.lens.personalization.backing .~ nil + + let vc = rewardCardInViewController( + language: language, + device: device, + project: project, + reward: reward + ) + + FBSnapshotVerifyView(vc.view, identifier: "\(rewardDescription)_lang_\(language)_device_\(device)") + } + } + } + + func testNonLive_BackedProject_BackedReward() { + combos([Language.en], [Device.phone4_7inch], allRewards).forEach { language, device, rewardTuple in + withEnvironment(language: language) { + let (rewardDescription, reward) = rewardTuple + + let project = Project.cosmicSurgery + |> Project.lens.state .~ .successful + |> Project.lens.personalization.isBacking .~ true + |> Project.lens.personalization.backing .~ ( + .template + |> Backing.lens.reward .~ reward + |> Backing.lens.rewardId .~ reward.id + |> Backing.lens.shippingAmount .~ 10 + |> Backing.lens.amount .~ 700 + ) + + let vc = rewardCardInViewController( + language: language, + device: device, + project: project, + reward: reward + ) + + FBSnapshotVerifyView(vc.view, identifier: "\(rewardDescription)_lang_\(language)_device_\(device)") + } + } + } + + func testNonLive_BackedProject_NonBackedReward() { + combos([Language.en], [Device.phone4_7inch], allRewards).forEach { language, device, rewardTuple in + withEnvironment(language: language) { + let (rewardDescription, reward) = rewardTuple + + let project = Project.cosmicSurgery + |> Project.lens.state .~ .successful + |> Project.lens.personalization.isBacking .~ true + |> Project.lens.personalization.backing .~ ( + .template + |> Backing.lens.reward .~ Reward.otherReward + |> Backing.lens.rewardId .~ Reward.otherReward.id + |> Backing.lens.shippingAmount .~ 10 + |> Backing.lens.amount .~ 700 + ) + + let vc = rewardCardInViewController( + language: language, + device: device, + project: project, + reward: reward + ) + + FBSnapshotVerifyView(vc.view, identifier: "\(rewardDescription)_lang_\(language)_device_\(device)") + } + } + } + + func testNonLive_NonBackedProject() { + combos([Language.en], [Device.phone4_7inch], allRewards).forEach { language, device, rewardTuple in + withEnvironment(language: language) { + let (rewardDescription, reward) = rewardTuple + + let project = Project.cosmicSurgery + |> Project.lens.state .~ .successful + |> Project.lens.personalization.isBacking .~ false + + let vc = rewardCardInViewController( + language: language, + device: device, + project: project, + reward: reward + ) + + FBSnapshotVerifyView(vc.view, identifier: "\(rewardDescription)_lang_\(language)_device_\(device)") + } + } + } + + func testLive_BackedProject_BackedReward_Errored() { + // Filter these out because they aren't states we can get to + let filteredRewards = allRewards + .filter { (name, _) -> Bool in + !name.lowercased().contains("unavailable") + } + + combos([Language.en], [Device.phone4_7inch], filteredRewards).forEach { language, device, rewardTuple in + withEnvironment(language: language) { + let (rewardDescription, reward) = rewardTuple + + let project = Project.cosmicSurgery + |> Project.lens.state .~ .live + |> Project.lens.personalization.isBacking .~ true + |> Project.lens.personalization.backing .~ ( + .template + |> Backing.lens.reward .~ reward + |> Backing.lens.rewardId .~ reward.id + |> Backing.lens.shippingAmount .~ 10 + |> Backing.lens.amount .~ 700 + |> Backing.lens.status .~ .errored + ) + + let vc = rewardCardInViewController( + language: language, + device: device, + project: project, + reward: reward + ) + + FBSnapshotVerifyView(vc.view, identifier: "\(rewardDescription)_lang_\(language)_device_\(device)") + } + } + } + + func testLive_BackedProject_NonBackedReward_Errored() { + combos([Language.en], [Device.phone4_7inch], allRewards).forEach { language, device, rewardTuple in + withEnvironment(language: language) { + let (rewardDescription, reward) = rewardTuple + + let project = Project.cosmicSurgery + |> Project.lens.state .~ .live + |> Project.lens.personalization.isBacking .~ true + |> Project.lens.personalization.backing .~ ( + .template + |> Backing.lens.reward .~ Reward.otherReward + |> Backing.lens.rewardId .~ Reward.otherReward.id + |> Backing.lens.shippingAmount .~ 10 + |> Backing.lens.amount .~ 700 + |> Backing.lens.status .~ .errored + ) + + let vc = rewardCardInViewController( + language: language, + device: device, + project: project, + reward: reward + ) + + FBSnapshotVerifyView(vc.view, identifier: "\(rewardDescription)_lang_\(language)_device_\(device)") + } + } + } + + override func tearDown() { + AppEnvironment.popEnvironment() + super.tearDown() + } +} + +private func rewardCardInViewController( + language _: Language, device: Device, project: Project, reward: Reward +) -> UIViewController { + let view = RewardCardContainerView(frame: .zero) + |> \.translatesAutoresizingMaskIntoConstraints .~ false + view.configure(with: (project: project, reward: .init(left: reward))) + + let controller = UIViewController(nibName: nil, bundle: nil) + let (parent, _) = traitControllers(device: device, orientation: .portrait, child: controller) + _ = controller.view + |> checkoutBackgroundStyle + controller.view.addSubview(view) + controller.view.layoutMargins = .init(all: Styles.grid(2)) + + NSLayoutConstraint.activate([ + view.leadingAnchor.constraint(equalTo: controller.view.layoutMarginsGuide.leadingAnchor), + view.topAnchor.constraint(equalTo: controller.view.layoutMarginsGuide.topAnchor), + view.trailingAnchor.constraint(equalTo: controller.view.layoutMarginsGuide.trailingAnchor), + view.bottomAnchor.constraint(lessThanOrEqualTo: controller.view.layoutMarginsGuide.bottomAnchor) + ]) + + view.setNeedsLayout() + + return parent +} + +let allRewards: [(String, Reward)] = { + let availableLimitedReward = Reward.postcards + |> Reward.lens.limit .~ 100 + |> Reward.lens.remaining .~ 25 + let availableTimebasedReward = Reward.postcards + |> Reward.lens.limit .~ nil + |> Reward.lens.remaining .~ nil + |> Reward.lens.endsAt .~ (MockDate().timeIntervalSince1970 + 60.0 * 60.0 * 24.0) + let availableLimitedTimebasedReward = Reward.postcards + |> Reward.lens.limit .~ 100 + |> Reward.lens.remaining .~ 25 + |> Reward.lens.endsAt .~ (MockDate().timeIntervalSince1970 + 60.0 * 60.0 * 24.0) + let availableNonLimitedReward = Reward.postcards + |> Reward.lens.limit .~ nil + |> Reward.lens.remaining .~ nil + |> Reward.lens.endsAt .~ nil + + let unavailableLimitedReward = Reward.postcards + |> Reward.lens.limit .~ 100 + |> Reward.lens.remaining .~ 0 + let unavailableTimebasedReward = Reward.postcards + |> Reward.lens.limit .~ nil + |> Reward.lens.remaining .~ nil + |> Reward.lens.endsAt .~ (MockDate().date.timeIntervalSince1970 - 1) + let unavailableLimitedTimebasedReward = Reward.postcards + |> Reward.lens.limit .~ 100 + |> Reward.lens.remaining .~ 0 + |> Reward.lens.endsAt .~ (MockDate().date.timeIntervalSince1970 - 1) + + return [ + ("AvailableLimitedReward", availableLimitedReward), + ("AvailableTimebasedReward", availableTimebasedReward), + ("AvailableLimitedTimebasedReward", availableLimitedTimebasedReward), + ("AvailableNonLimitedReward", availableNonLimitedReward), + ("UnavailableLimitedReward", unavailableLimitedReward), + ("UnavailableTimebasedReward", unavailableTimebasedReward), + ("UnavailableLimitedTimebasedReward", unavailableLimitedTimebasedReward), + ("NoReward", Reward.noReward) + ] +}() diff --git a/Kickstarter-iOS/Views/RewardCardView.swift b/Kickstarter-iOS/Views/RewardCardView.swift index a78ab68830..249c5f8aca 100644 --- a/Kickstarter-iOS/Views/RewardCardView.swift +++ b/Kickstarter-iOS/Views/RewardCardView.swift @@ -42,7 +42,6 @@ public final class RewardCardView: UIView { |> \.contentInsetAdjustmentBehavior .~ UIScrollView.ContentInsetAdjustmentBehavior.always |> \.dataSource .~ self.pillDataSource |> \.delegate .~ self - |> \.isHidden .~ true |> \.translatesAutoresizingMaskIntoConstraints .~ false }() @@ -59,7 +58,6 @@ public final class RewardCardView: UIView { private let stateImageViewContainer: UIView = { UIView(frame: .zero) - |> \.isHidden .~ true |> \.translatesAutoresizingMaskIntoConstraints .~ false }() @@ -144,9 +142,6 @@ public final class RewardCardView: UIView { |> baseRewardLabelStyle |> minimumPriceConversionLabelStyle - _ = self.stateImageView - |> stateImageViewStyle - _ = self.stateImageViewContainer |> stateImageViewContainerStyle @@ -162,9 +157,28 @@ public final class RewardCardView: UIView { self.descriptionLabel.rac.text = self.viewModel.outputs.descriptionLabelText self.includedItemsStackView.rac.hidden = self.viewModel.outputs.includedItemsStackViewHidden self.minimumPriceLabel.rac.text = self.viewModel.outputs.rewardMinimumLabelText + self.pillCollectionView.rac.hidden = self.viewModel.outputs.pillCollectionViewHidden self.rewardTitleLabel.rac.hidden = self.viewModel.outputs.rewardTitleLabelHidden self.rewardTitleLabel.rac.text = self.viewModel.outputs.rewardTitleLabelText + self.viewModel.outputs.stateIconImageName + .observeForUI() + .observeValues { [weak self] imageName in + self?.stateImageView.image = image(named: imageName) + } + + self.stateImageView.rac.tintColor = self.viewModel.outputs.stateIconImageTintColor + self.stateImageViewContainer.rac.backgroundColor = self.viewModel.outputs + .stateIconImageViewContainerBackgroundColor + self.stateImageViewContainer.rac.hidden = self.viewModel.outputs + .stateIconImageViewContainerHidden + + self.viewModel.outputs.stateIconImageName + .observeForUI() + .observeValues { [weak self] imageName in + self?.stateImageView.image = image(named: imageName) + } + self.viewModel.outputs.items .observeForUI() .observeValues { [weak self] in self?.load(items: $0) } @@ -184,8 +198,12 @@ public final class RewardCardView: UIView { ?|> \.isUserInteractionEnabled .~ isUserInteractionEnabled } - self.pillDataSource.load(["Ends in 3 days", "16 left", "16 left"]) - self.pillCollectionView.reloadData() + self.viewModel.outputs.reloadPills + .observeForUI() + .observeValues { [weak self] values in + self?.pillDataSource.load(values) + self?.pillCollectionView.reloadData() + } } // MARK: - Private Helpers @@ -364,15 +382,8 @@ private let sectionBodyLabelStyle: LabelStyle = { label in |> \.font .~ UIFont.ksr_body() } -private let stateImageViewStyle: ImageViewStyle = { imageView in - imageView - |> \.image .~ UIImage(named: "checkmark-reward") - |> \.tintColor .~ UIColor.ksr_blue_500 -} - private let stateImageViewContainerStyle: ViewStyle = { view in view - |> \.backgroundColor .~ UIColor.ksr_blue_500.withAlphaComponent(0.06) |> \.layer.cornerRadius .~ 15 } diff --git a/Kickstarter.xcodeproj/project.pbxproj b/Kickstarter.xcodeproj/project.pbxproj index 2ed3a54b87..b67c2edd30 100644 --- a/Kickstarter.xcodeproj/project.pbxproj +++ b/Kickstarter.xcodeproj/project.pbxproj @@ -83,6 +83,7 @@ 37096C3022BC238C003D1F40 /* MockFeedbackGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37096C2F22BC238C003D1F40 /* MockFeedbackGenerator.swift */; }; 37096C3422BC24DD003D1F40 /* UIFeedbackGeneratorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37096C3322BC24DD003D1F40 /* UIFeedbackGeneratorType.swift */; }; 37096C3522BC282E003D1F40 /* MockAppEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37096C3122BC23AD003D1F40 /* MockAppEnvironment.swift */; }; + 370ACB00225D337900C8745F /* PledgeAmountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370ACAFF225D337900C8745F /* PledgeAmountViewController.swift */; }; 370BE71622541C8100B44DB2 /* UIViewController+URL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370BE71522541C8100B44DB2 /* UIViewController+URL.swift */; }; 370F527A2254267900F159B9 /* UIApplicationType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370F52792254267900F159B9 /* UIApplicationType.swift */; }; 370F52B3225426C700F159B9 /* UIApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370F52B2225426C700F159B9 /* UIApplication.swift */; }; @@ -193,7 +194,6 @@ 77216D9820F3D2E40061BE82 /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77216D9720F3D2E40061BE82 /* SettingsViewController.swift */; }; 77277C3022B2BF53002B2321 /* FeatureFlagToolsViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77277C2F22B2BF53002B2321 /* FeatureFlagToolsViewModelTests.swift */; }; 77277C3222B2CA33002B2321 /* FeatureFlagToolsViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77277C3122B2CA33002B2321 /* FeatureFlagToolsViewControllerTests.swift */; }; - 77321A0122F89B3000470438 /* PledgeAmountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77321A0022F89B3000470438 /* PledgeAmountViewController.swift */; }; 774527DE21B1E0480072E590 /* MessageBannerViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 774527DD21B1E0480072E590 /* MessageBannerViewController.xib */; }; 7748438022D8DA3800508C9B /* Instantiable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7748437F22D8DA3800508C9B /* Instantiable.swift */; }; 7748438422D8DE8200508C9B /* PledgeContinueViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7748438322D8DE8200508C9B /* PledgeContinueViewController.swift */; }; @@ -280,6 +280,7 @@ 80EAEF001D243A7A008C2353 /* BackingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80EAEEFF1D243A7A008C2353 /* BackingViewModel.swift */; }; 80EAEF051D243C4E008C2353 /* Backing.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 80EAEF031D243C4E008C2353 /* Backing.storyboard */; }; 80EAEF071D243FC7008C2353 /* BackingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80EAEF011D243B69008C2353 /* BackingViewController.swift */; }; + 8A23EF0822F11470001262E1 /* RewardCardContainerViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A23EF0722F11470001262E1 /* RewardCardContainerViewTests.swift */; }; 8A8099EB22E213F100373E66 /* RewardCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A8099E922E213F100373E66 /* RewardCardView.swift */; }; 8A8099EC22E213F100373E66 /* RewardCardContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A8099EA22E213F100373E66 /* RewardCardContainerView.swift */; }; 8A8099F122E2142C00373E66 /* RewardCardViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A8099ED22E2142C00373E66 /* RewardCardViewModel.swift */; }; @@ -1394,6 +1395,7 @@ 37096C2F22BC238C003D1F40 /* MockFeedbackGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockFeedbackGenerator.swift; sourceTree = ""; }; 37096C3122BC23AD003D1F40 /* MockAppEnvironment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAppEnvironment.swift; sourceTree = ""; }; 37096C3322BC24DD003D1F40 /* UIFeedbackGeneratorType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIFeedbackGeneratorType.swift; sourceTree = ""; }; + 370ACAFF225D337900C8745F /* PledgeAmountViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PledgeAmountViewController.swift; sourceTree = ""; }; 370BE71522541C8100B44DB2 /* UIViewController+URL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+URL.swift"; sourceTree = ""; }; 370BE74E22541C8F00B44DB2 /* UIViewController+URLTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+URLTests.swift"; sourceTree = ""; }; 370F52792254267900F159B9 /* UIApplicationType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIApplicationType.swift; sourceTree = ""; }; @@ -1506,7 +1508,6 @@ 77216D9720F3D2E40061BE82 /* SettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; }; 77277C2F22B2BF53002B2321 /* FeatureFlagToolsViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureFlagToolsViewModelTests.swift; sourceTree = ""; }; 77277C3122B2CA33002B2321 /* FeatureFlagToolsViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureFlagToolsViewControllerTests.swift; sourceTree = ""; }; - 77321A0022F89B3000470438 /* PledgeAmountViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PledgeAmountViewController.swift; sourceTree = ""; }; 774527DD21B1E0480072E590 /* MessageBannerViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MessageBannerViewController.xib; sourceTree = ""; }; 7748437F22D8DA3800508C9B /* Instantiable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Instantiable.swift; sourceTree = ""; }; 7748438322D8DE8200508C9B /* PledgeContinueViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PledgeContinueViewController.swift; sourceTree = ""; }; @@ -1593,6 +1594,7 @@ 80EAEEFF1D243A7A008C2353 /* BackingViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackingViewModel.swift; sourceTree = ""; }; 80EAEF011D243B69008C2353 /* BackingViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackingViewController.swift; sourceTree = ""; }; 80EAEF031D243C4E008C2353 /* Backing.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Backing.storyboard; sourceTree = ""; }; + 8A23EF0722F11470001262E1 /* RewardCardContainerViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RewardCardContainerViewTests.swift; sourceTree = ""; }; 8A8099E922E213F100373E66 /* RewardCardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RewardCardView.swift; sourceTree = ""; }; 8A8099EA22E213F100373E66 /* RewardCardContainerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RewardCardContainerView.swift; sourceTree = ""; }; 8A8099ED22E2142C00373E66 /* RewardCardViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RewardCardViewModel.swift; sourceTree = ""; }; @@ -2446,7 +2448,6 @@ D09D4ECF2289D63500C33B77 /* Curry.framework in Frameworks */, D0B7124922AEEDF900317BAF /* FBSDKCoreKit.framework in Frameworks */, D08C68AA22AF105B001ED5E8 /* FBSDKLoginKit.framework in Frameworks */, - D09D4ECF2289D63500C33B77 /* Curry.framework in Frameworks */, A76127C01C93100C00EDCCB9 /* Library.framework in Frameworks */, D09D4ED52289D6B100C33B77 /* OnePasswordExtension.framework in Frameworks */, D0D58DC62257FD0200532AC1 /* Prelude.framework in Frameworks */, @@ -2724,6 +2725,7 @@ 015706BA1E68DE580087DD68 /* ProfileSortBarView.swift */, A78012641D2EEA620027396E /* ReferralChartView.swift */, 8A8099EA22E213F100373E66 /* RewardCardContainerView.swift */, + 8A23EF0722F11470001262E1 /* RewardCardContainerViewTests.swift */, 8A8099E922E213F100373E66 /* RewardCardView.swift */, D0A787BC2204D865006AE4F4 /* SelectCurrencyTableViewHeader.swift */, 37D671F6221E61B600B6D415 /* SettingsFooterView.swift */, @@ -2890,7 +2892,7 @@ A7ED203E1E8323E900BFFA01 /* MessageThreadsViewControllerTests.swift */, D63BBCCF217E5460007E01F0 /* PaymentMethodsViewController.swift */, D6F7416F21836C3D00C2DDA2 /* PaymentMethodsViewControllerTests.swift */, - 77321A0022F89B3000470438 /* PledgeAmountViewController.swift */, + 370ACAFF225D337900C8745F /* PledgeAmountViewController.swift */, 7748438322D8DE8200508C9B /* PledgeContinueViewController.swift */, D79A054A225E9B6B004BC6A8 /* PledgeDescriptionViewController.swift */, 8A8099FE22E21F9700373E66 /* PledgeDescriptionViewControllerTests.swift */, @@ -4465,8 +4467,8 @@ 3705CF0F222EE7670025D37E /* EnvironmentVariables.swift in Sources */, A73379601D0EDFEE00C91445 /* UIViewController-Preparation.swift in Sources */, A72C3A951D00F6C70075227E /* DiscoveryPageViewModel.swift in Sources */, - D0D77C1E22D3FC3400356FEA /* UIPageViewController+ThreadSafety.swift in Sources */, 37EB3E4C228CF4A400076E4C /* NumberFormatter.swift in Sources */, + D0D77C1E22D3FC3400356FEA /* UIPageViewController+ThreadSafety.swift in Sources */, A7F441C71D005A9400FE6FC5 /* MessageCellViewModel.swift in Sources */, 59673CBF1D50EE9B0035AFD9 /* VideoViewModel.swift in Sources */, 9D10B91B1D35407C008B8045 /* String+Truncate.swift in Sources */, @@ -4957,7 +4959,6 @@ A71003E31CDD077200B4F4D7 /* MessageCell.swift in Sources */, 01B3B0301E78890800B8BF46 /* BackerDashboardPagesDataSource.swift in Sources */, 8072F44F1D46BAA400999EF1 /* UpdatePreviewViewModel.swift in Sources */, - 77321A0122F89B3000470438 /* PledgeAmountViewController.swift in Sources */, A7C795B31C873AC90081977F /* ActivitiesViewController.swift in Sources */, A731BF8D1D1EE44E00A734AC /* UpdateViewController.swift in Sources */, A75798911D6A201F0063CEEC /* DebugPushNotificationsViewController.swift in Sources */, @@ -5054,6 +5055,7 @@ 597073B21D07281800B00444 /* ProjectNotificationCell.swift in Sources */, 01DEFB961CB44A5D003709C0 /* TwoFactorViewController.swift in Sources */, 3767EDAD22CFFEF20088E8E4 /* ShippingRulesTableViewController.swift in Sources */, + 370ACB00225D337900C8745F /* PledgeAmountViewController.swift in Sources */, A75AB2261C8B407F002FC3E6 /* ActivityFriendBackingCell.swift in Sources */, A731BF901D1EE4CD00A734AC /* UpdateViewModel.swift in Sources */, A72C3AB51D00FB1F0075227E /* DiscoveryExpandableRowCell.swift in Sources */, @@ -5152,6 +5154,7 @@ A7ED201F1E83232A00BFFA01 /* XCTestCase+AppEnvironment.swift in Sources */, A7ED20171E83229E00BFFA01 /* DiscoveryProjectsDataSourceTest.swift in Sources */, 774ACC19225F8DC30097FCE6 /* ProjectPamphletViewControllerTests.swift in Sources */, + 8A23EF0822F11470001262E1 /* RewardCardContainerViewTests.swift in Sources */, A7ED20451E8323E900BFFA01 /* DashboardViewControllerTests.swift in Sources */, D764377C224174B700DAFC9E /* SharedFunctionsTests.swift in Sources */, A7ED20141E83229E00BFFA01 /* DashboardProjectsDrawerDataSourceTests.swift in Sources */, diff --git a/KsApi/models/Config.swift b/KsApi/models/Config.swift index 6b9b09deaf..8f47f34e89 100644 --- a/KsApi/models/Config.swift +++ b/KsApi/models/Config.swift @@ -1,5 +1,3 @@ -import Prelude - public enum Experiment { public enum Name: String { case creatorsNameDiscovery = "show_created_by_discovery" diff --git a/KsApi/models/templates/RewardTemplates.swift b/KsApi/models/templates/RewardTemplates.swift index 16bbacbff6..7aba60839a 100644 --- a/KsApi/models/templates/RewardTemplates.swift +++ b/KsApi/models/templates/RewardTemplates.swift @@ -38,4 +38,39 @@ extension Reward { startsAt: nil, title: nil ) + + public static let otherReward = Reward( + backersCount: nil, + description: "", + endsAt: nil, + estimatedDeliveryOn: nil, + id: 9_999, + limit: nil, + minimum: 0, + remaining: nil, + rewardsItems: [], + shipping: Reward.Shipping( + enabled: false, preference: nil, summary: nil + ), + startsAt: nil, + title: nil + ) + + public static let postcards = Reward.template + |> Reward.lens.id .~ 20 + |> Reward.lens.minimum .~ 6 + |> Reward.lens.limit .~ 100 + |> Reward.lens.remaining .~ 50 + |> Reward.lens.backersCount .~ 23 + |> Reward.lens.title .~ "Postcards" + |> Reward.lens.description .~ "Pack of 5 postcards - images from the Cosmic Surgery series." + |> Reward.lens.rewardsItems .~ Array(1...5) + .map { number in + RewardsItem.template + |> RewardsItem.lens.quantity .~ 1 + |> RewardsItem.lens.item .~ ( + .template + |> Item.lens.name .~ "Post card \(number)" + ) + } } diff --git a/Library/Strings.swift b/Library/Strings.swift index a80853b12e..6eb2ac0b67 100644 --- a/Library/Strings.swift +++ b/Library/Strings.swift @@ -2784,6 +2784,23 @@ contributeurs" substitutions: [:] ) } + /** + "Fix your payment method" + + - **en**: "Fix your payment method" + - **de**: "Zahlungsmethode ändern" + - **es**: "Corrige tu método de pago" + - **fr**: "Corriger votre moyen de paiement" + - **ja**: "お支払い方法を修正" + */ + public static func Fix_your_payment_method() -> String { + return localizedString( + key: "Fix_your_payment_method", + defaultValue: "Fix your payment method", + count: nil, + substitutions: [:] + ) + } /** "Follow %{friend_name}" @@ -4521,6 +4538,23 @@ with friends." substitutions: [:] ) } + /** + "No longer available" + + - **en**: "No longer available" + - **de**: "Nicht mehr verfügbar" + - **es**: "Ya no está disponible" + - **fr**: "Indisponible" + - **ja**: "利用できなくなりました" + */ + public static func No_longer_available() -> String { + return localizedString( + key: "No_longer_available", + defaultValue: "No longer available", + count: nil, + substitutions: [:] + ) + } /** "No messages" diff --git a/Library/Styles/CheckoutStyles.swift b/Library/Styles/CheckoutStyles.swift index 4aafc11de4..fa6cfe7cb1 100644 --- a/Library/Styles/CheckoutStyles.swift +++ b/Library/Styles/CheckoutStyles.swift @@ -1,6 +1,26 @@ import Prelude import UIKit +// MARK: - Types + +public enum ButtonStyleType: Equatable { + case apricot + case black + case blue + case green + case none + + public var style: ButtonStyle { + switch self { + case .apricot: return apricotButtonStyle + case .black: return blackButtonStyle + case .blue: return blueButtonStyle + case .green: return greenButtonStyle + case .none: return { $0 } + } + } +} + // MARK: - Constants public enum CheckoutConstants { diff --git a/Library/ViewModels/DeprecatedRewardCellViewModelTests.swift b/Library/ViewModels/DeprecatedRewardCellViewModelTests.swift index 88fcc47d67..e7da515f03 100644 --- a/Library/ViewModels/DeprecatedRewardCellViewModelTests.swift +++ b/Library/ViewModels/DeprecatedRewardCellViewModelTests.swift @@ -133,7 +133,7 @@ final class DeprecatedRewardCellViewModelTests: TestCase { self.titleLabelText.assertValues(["The goods"]) } - // MARK: - Conversion Label + // MARK: Conversion Label func testConversionLabel_US_User_US_Project_ConfiguredWithReward() { let project = .template |> Project.lens.country .~ .us diff --git a/Library/ViewModels/ProjectPamphletViewModel.swift b/Library/ViewModels/ProjectPamphletViewModel.swift index f9a1187532..0678e39ea2 100644 --- a/Library/ViewModels/ProjectPamphletViewModel.swift +++ b/Library/ViewModels/ProjectPamphletViewModel.swift @@ -1,7 +1,6 @@ import KsApi import Prelude import ReactiveSwift - public protocol ProjectPamphletViewModelInputs { /// Call when "Back this project" is tapped func backThisProjectTapped() diff --git a/Library/ViewModels/RewardCardContainerViewModel.swift b/Library/ViewModels/RewardCardContainerViewModel.swift index b371762a80..b616ee6e9c 100644 --- a/Library/ViewModels/RewardCardContainerViewModel.swift +++ b/Library/ViewModels/RewardCardContainerViewModel.swift @@ -8,8 +8,10 @@ public protocol RewardCardContainerViewModelInputs { } public protocol RewardCardContainerViewModelOutputs { + var pledgeButtonStyleType: Signal { get } var pledgeButtonEnabled: Signal { get } - var pledgeButtonTitleText: Signal { get } + var pledgeButtonHidden: Signal { get } + var pledgeButtonTitleText: Signal { get } var rewardSelected: Signal { get } func currentReward(is reward: Reward) -> Bool } @@ -25,6 +27,8 @@ public final class RewardCardContainerViewModel: RewardCardContainerViewModelTyp let projectAndRewardOrBacking: Signal<(Project, Either), Never> = self.projectAndRewardOrBackingProperty.signal.skipNil() + let project: Signal = projectAndRewardOrBacking.map(first) + let reward: Signal = projectAndRewardOrBacking .map { project, rewardOrBacking -> Reward in rewardOrBacking.left @@ -33,15 +37,22 @@ public final class RewardCardContainerViewModel: RewardCardContainerViewModelTyp ?? Reward.noReward } + let projectAndReward = Signal.zip(project, reward) + self.currentRewardProperty <~ reward - let rewardAvailable = reward - .map { $0.remaining == 0 }.negate() + let pledgeButtonTitleText = projectAndReward + .map(pledgeButtonTitle(project:reward:)) + + self.pledgeButtonTitleText = pledgeButtonTitleText - self.pledgeButtonTitleText = projectAndRewardOrBacking - .map(pledgeButtonTitle(project:rewardOrBacking:)) + self.pledgeButtonStyleType = projectAndReward + .map(buttonStyleType(project:reward:)) - self.pledgeButtonEnabled = rewardAvailable + self.pledgeButtonEnabled = projectAndReward + .map(pledgeButtonIsEnabled(project:reward:)) + + self.pledgeButtonHidden = pledgeButtonTitleText.map(isNil) self.rewardSelected = reward .takeWhen(self.pledgeButtonTappedProperty.signal) @@ -58,8 +69,10 @@ public final class RewardCardContainerViewModel: RewardCardContainerViewModelTyp self.pledgeButtonTappedProperty.value = () } + public let pledgeButtonStyleType: Signal public let pledgeButtonEnabled: Signal - public let pledgeButtonTitleText: Signal + public let pledgeButtonHidden: Signal + public let pledgeButtonTitleText: Signal public let rewardSelected: Signal private let currentRewardProperty = MutableProperty(nil) @@ -84,12 +97,84 @@ private func backingReward(fromProject project: Project) -> Reward? { .coalesceWith(.noReward) } -private func pledgeButtonTitle(project: Project, rewardOrBacking: Either) -> String { +private func pledgeButtonTitle(project: Project, reward: Reward) -> String? { + let projectBackingState = RewardCellProjectBackingStateType.state(with: project) + let isBackingThisReward = userIsBacking(reward: reward, inProject: project) + let isRewardAvailable = rewardIsAvailable(reward: reward) + + switch (projectBackingState, isBackingThisReward, isRewardAvailable) { + case (.backedError, false, true): + return Strings.Select_this_reward_instead() + case (.backedError, true, _): + return Strings.Fix_your_payment_method() + case (.backed(.live), false, true): + return Strings.Select_this_reward_instead() + case (.backed(.live), true, _): + return Strings.Manage_your_pledge() + case (.nonBacked(.live), _, true): + return nonBackedPledgeButtonTitle(project: project, reward: reward) + case (.backed(.nonLive), true, _): + return Strings.View_your_pledge() + case (.backed(.nonLive), false, _), + (.nonBacked(.nonLive), _, _): + return nil + case (_, _, false): + return Strings.No_longer_available() + } +} + +private func buttonStyleType(project: Project, reward: Reward) -> ButtonStyleType { + let projectBackingState = RewardCellProjectBackingStateType.state(with: project) + let isBackingThisReward = userIsBacking(reward: reward, inProject: project) + + switch projectBackingState { + case .backedError: + if isBackingThisReward { + return .apricot + } + case .backed(.live): + if isBackingThisReward { + return .blue + } + case .nonBacked(.live): + return .green + case .backed(.nonLive): + if isBackingThisReward { + return .black + } + return .none + case .nonBacked(.nonLive): + return .none + } + + return .green +} + +private func nonBackedPledgeButtonTitle(project: Project, reward: Reward) -> String { let minimumFormattedAmount = formattedAmountForRewardOrBacking( project: project, - rewardOrBacking: rewardOrBacking + rewardOrBacking: .init(left: reward) ) - return project.personalization.isBacking == true - ? Strings.Select_this_reward_instead() - : Strings.rewards_title_pledge_reward_currency_or_more(reward_currency: minimumFormattedAmount) + + return Strings.rewards_title_pledge_reward_currency_or_more(reward_currency: minimumFormattedAmount) +} + +private func pledgeButtonIsEnabled(project: Project, reward: Reward) -> Bool { + let isAvailable = rewardIsAvailable(reward: reward) + let isBacking = userIsBacking(reward: reward, inProject: project) + + return (project.state == .live && isAvailable) || isBacking +} + +private func rewardIsAvailable(reward: Reward) -> Bool { + let isLimited = reward.remaining != nil || reward.endsAt != nil + + guard isLimited else { return true } + + let remaining = reward.remaining.coalesceWith(0) > 0 + let endsAt = reward.endsAt.coalesceWith(0) + let now = AppEnvironment.current.dateType.init().timeIntervalSince1970 + let timeLimitNotReached = endsAt > now + + return remaining || timeLimitNotReached } diff --git a/Library/ViewModels/RewardCardContainerViewModelTests.swift b/Library/ViewModels/RewardCardContainerViewModelTests.swift index 0438feb361..5f10ba770b 100644 --- a/Library/ViewModels/RewardCardContainerViewModelTests.swift +++ b/Library/ViewModels/RewardCardContainerViewModelTests.swift @@ -9,55 +9,463 @@ import XCTest final class RewardCardContainerViewModelTests: TestCase { fileprivate let vm: RewardCardContainerViewModelType = RewardCardContainerViewModel() + private let pledgeButtonStyleType = TestObserver() private let pledgeButtonEnabled = TestObserver() - private let pledgeButtonTitleText = TestObserver() + private let pledgeButtonHidden = TestObserver() + private let pledgeButtonTitleText = TestObserver() private let rewardSelected = TestObserver() + let availableLimitedReward = Reward.postcards + |> Reward.lens.limit .~ 100 + |> Reward.lens.remaining .~ 25 + let availableTimebasedReward = Reward.postcards + |> Reward.lens.limit .~ nil + |> Reward.lens.remaining .~ nil + |> Reward.lens.endsAt .~ (MockDate().timeIntervalSince1970 + 60.0 * 60.0 * 24.0) + let availableLimitedTimebasedReward = Reward.postcards + |> Reward.lens.limit .~ 100 + |> Reward.lens.remaining .~ 25 + |> Reward.lens.endsAt .~ (MockDate().timeIntervalSince1970 + 60.0 * 60.0 * 24.0) + let availableNonLimitedReward = Reward.postcards + |> Reward.lens.limit .~ nil + |> Reward.lens.remaining .~ nil + |> Reward.lens.endsAt .~ nil + + let unavailableLimitedReward = Reward.postcards + |> Reward.lens.limit .~ 100 + |> Reward.lens.remaining .~ 0 + let unavailableTimebasedReward = Reward.postcards + |> Reward.lens.limit .~ nil + |> Reward.lens.remaining .~ nil + |> Reward.lens.endsAt .~ (MockDate().date.timeIntervalSince1970 - 1) + let unavailableLimitedTimebasedReward = Reward.postcards + |> Reward.lens.limit .~ 100 + |> Reward.lens.remaining .~ 0 + |> Reward.lens.endsAt .~ (MockDate().date.timeIntervalSince1970 - 1) + + private var allRewards: [Reward] { + return [ + availableLimitedReward, + availableTimebasedReward, + availableLimitedTimebasedReward, + availableNonLimitedReward, + unavailableLimitedReward, + unavailableTimebasedReward, + unavailableLimitedTimebasedReward, + Reward.noReward + ] + } + override func setUp() { super.setUp() + self.vm.outputs.pledgeButtonStyleType.observe(self.pledgeButtonStyleType.observer) self.vm.outputs.pledgeButtonEnabled.observe(self.pledgeButtonEnabled.observer) + self.vm.outputs.pledgeButtonHidden.observe(self.pledgeButtonHidden.observer) self.vm.outputs.pledgeButtonTitleText.observe(self.pledgeButtonTitleText.observer) self.vm.outputs.rewardSelected.observe(self.rewardSelected.observer) } - // MARK: - Pledge Button + func testLive_BackedProject_BackedReward() { + self.pledgeButtonStyleType.assertValueCount(0) + self.pledgeButtonEnabled.assertValueCount(0) + self.pledgeButtonHidden.assertValueCount(0) + self.pledgeButtonTitleText.assertValueCount(0) + + for (index, reward) in self.allRewards.enumerated() { + let project = Project.cosmicSurgery + |> Project.lens.state .~ .live + |> Project.lens.personalization.isBacking .~ true + |> Project.lens.personalization.backing .~ ( + .template + |> Backing.lens.reward .~ reward + |> Backing.lens.rewardId .~ reward.id + |> Backing.lens.shippingAmount .~ 10 + |> Backing.lens.amount .~ 700 + ) + + self.vm.inputs.configureWith(project: project, rewardOrBacking: .init(reward)) + + let emissionCount = index + 1 + + self.pledgeButtonStyleType.assertValueCount(emissionCount) + self.pledgeButtonEnabled.assertValueCount(emissionCount) + self.pledgeButtonHidden.assertValueCount(emissionCount) + self.pledgeButtonTitleText.assertValueCount(emissionCount) + } + + self.pledgeButtonStyleType.assertValueCount(self.allRewards.count) + self.pledgeButtonEnabled.assertValueCount(self.allRewards.count) + self.pledgeButtonHidden.assertValueCount(self.allRewards.count) + self.pledgeButtonTitleText.assertValueCount(self.allRewards.count) + + self.pledgeButtonStyleType.assertValues([.blue, .blue, .blue, .blue, .blue, .blue, .blue, .blue]) + self.pledgeButtonEnabled.assertValues([true, true, true, true, true, true, true, true]) + self.pledgeButtonHidden.assertValues([false, false, false, false, false, false, false, false]) + self.pledgeButtonTitleText.assertValues([ + "Manage your pledge", + "Manage your pledge", + "Manage your pledge", + "Manage your pledge", + "Manage your pledge", + "Manage your pledge", + "Manage your pledge", + "Manage your pledge" + ]) + } + + func testLive_BackedProject_NonBackedReward() { + self.pledgeButtonStyleType.assertValueCount(0) + self.pledgeButtonEnabled.assertValueCount(0) + self.pledgeButtonHidden.assertValueCount(0) + self.pledgeButtonTitleText.assertValueCount(0) + + for (index, reward) in self.allRewards.enumerated() { + let project = Project.cosmicSurgery + |> Project.lens.state .~ .live + |> Project.lens.personalization.isBacking .~ true + |> Project.lens.personalization.backing .~ ( + .template + |> Backing.lens.reward .~ Reward.otherReward + |> Backing.lens.rewardId .~ Reward.otherReward.id + |> Backing.lens.shippingAmount .~ 10 + |> Backing.lens.amount .~ 700 + ) + + self.vm.inputs.configureWith(project: project, rewardOrBacking: .init(reward)) + + let emissionCount = index + 1 + + self.pledgeButtonStyleType.assertValueCount(emissionCount) + self.pledgeButtonEnabled.assertValueCount(emissionCount) + self.pledgeButtonHidden.assertValueCount(emissionCount) + self.pledgeButtonTitleText.assertValueCount(emissionCount) + } + + self.pledgeButtonStyleType.assertValueCount(self.allRewards.count) + self.pledgeButtonEnabled.assertValueCount(self.allRewards.count) + self.pledgeButtonHidden.assertValueCount(self.allRewards.count) + self.pledgeButtonTitleText.assertValueCount(self.allRewards.count) + + self.pledgeButtonStyleType.assertValues([.green, .green, .green, .green, .green, .green, .green, .green]) + self.pledgeButtonEnabled.assertValues([true, true, true, true, false, false, false, true]) + self.pledgeButtonHidden.assertValues([false, false, false, false, false, false, false, false]) + self.pledgeButtonTitleText.assertValues([ + "Select this reward instead", + "Select this reward instead", + "Select this reward instead", + "Select this reward instead", + "No longer available", + "No longer available", + "No longer available", + "Select this reward instead" + ]) + } + + func testLive_NonBackedProject_LoggedIn() { + self.pledgeButtonStyleType.assertValueCount(0) + self.pledgeButtonEnabled.assertValueCount(0) + self.pledgeButtonHidden.assertValueCount(0) + self.pledgeButtonTitleText.assertValueCount(0) - func testPledgeButtonTitle_Reward_NotAllGone() { - let project = Project.template - |> Project.lens.country .~ .us + for (index, reward) in self.allRewards.enumerated() { + let project = Project.cosmicSurgery + |> Project.lens.state .~ .live + |> Project.lens.personalization.isBacking .~ false - let reward = Reward.template - |> Reward.lens.remaining .~ 10 - |> Reward.lens.minimum .~ 1_000 + self.vm.inputs.configureWith(project: project, rewardOrBacking: .init(reward)) - withEnvironment(locale: Locale(identifier: "en")) { - self.vm.inputs.configureWith(project: project, rewardOrBacking: .left(reward)) + let emissionCount = index + 1 - self.pledgeButtonTitleText.assertValues(["Pledge $1,000 or more"]) + self.pledgeButtonStyleType.assertValueCount(emissionCount) + self.pledgeButtonEnabled.assertValueCount(emissionCount) + self.pledgeButtonHidden.assertValueCount(emissionCount) + self.pledgeButtonTitleText.assertValueCount(emissionCount) } + + self.pledgeButtonStyleType.assertValueCount(self.allRewards.count) + self.pledgeButtonEnabled.assertValueCount(self.allRewards.count) + self.pledgeButtonHidden.assertValueCount(self.allRewards.count) + self.pledgeButtonTitleText.assertValueCount(self.allRewards.count) + + self.pledgeButtonStyleType.assertValues([.green, .green, .green, .green, .green, .green, .green, .green]) + self.pledgeButtonEnabled.assertValues([true, true, true, true, false, false, false, true]) + self.pledgeButtonHidden.assertValues([false, false, false, false, false, false, false, false]) + self.pledgeButtonTitleText.assertValues([ + "Pledge £6 or more", + "Pledge £6 or more", + "Pledge £6 or more", + "Pledge £6 or more", + "No longer available", + "No longer available", + "No longer available", + "Pledge £1 or more" + ]) } - func testPledgeButtonEnabled_Reward_NotAllGone() { - let project = Project.template - let reward = Reward.template - |> Reward.lens.remaining .~ 10 - |> Reward.lens.minimum .~ 1_000 + func testLive_NonBackedProject_LoggedOut() { + self.pledgeButtonStyleType.assertValueCount(0) + self.pledgeButtonEnabled.assertValueCount(0) + self.pledgeButtonHidden.assertValueCount(0) + self.pledgeButtonTitleText.assertValueCount(0) + + for (index, reward) in self.allRewards.enumerated() { + let project = Project.cosmicSurgery + |> Project.lens.state .~ .live + |> Project.lens.personalization.isBacking .~ nil + |> Project.lens.personalization.backing .~ nil + + self.vm.inputs.configureWith(project: project, rewardOrBacking: .init(reward)) + + let emissionCount = index + 1 - self.vm.inputs.configureWith(project: project, rewardOrBacking: .left(reward)) + self.pledgeButtonStyleType.assertValueCount(emissionCount) + self.pledgeButtonEnabled.assertValueCount(emissionCount) + self.pledgeButtonHidden.assertValueCount(emissionCount) + self.pledgeButtonTitleText.assertValueCount(emissionCount) + } + + self.pledgeButtonStyleType.assertValueCount(self.allRewards.count) + self.pledgeButtonEnabled.assertValueCount(self.allRewards.count) + self.pledgeButtonHidden.assertValueCount(self.allRewards.count) + self.pledgeButtonTitleText.assertValueCount(self.allRewards.count) - self.pledgeButtonEnabled.assertValues([true]) + self.pledgeButtonStyleType.assertValues([.green, .green, .green, .green, .green, .green, .green, .green]) + self.pledgeButtonEnabled.assertValues([true, true, true, true, false, false, false, true]) + self.pledgeButtonHidden.assertValues([false, false, false, false, false, false, false, false]) + self.pledgeButtonTitleText.assertValues([ + "Pledge £6 or more", + "Pledge £6 or more", + "Pledge £6 or more", + "Pledge £6 or more", + "No longer available", + "No longer available", + "No longer available", + "Pledge £1 or more" + ]) } - func testPledgeButtonEnabled_Reward_AllGone() { - let project = Project.template - let reward = Reward.template - |> Reward.lens.remaining .~ 0 - |> Reward.lens.minimum .~ 1_000 + func testNonLive_BackedProject_BackedReward() { + self.pledgeButtonStyleType.assertValueCount(0) + self.pledgeButtonEnabled.assertValueCount(0) + self.pledgeButtonHidden.assertValueCount(0) + self.pledgeButtonTitleText.assertValueCount(0) + + for (index, reward) in self.allRewards.enumerated() { + let project = Project.cosmicSurgery + |> Project.lens.state .~ .successful + |> Project.lens.personalization.isBacking .~ true + |> Project.lens.personalization.backing .~ ( + .template + |> Backing.lens.reward .~ reward + |> Backing.lens.rewardId .~ reward.id + |> Backing.lens.shippingAmount .~ 10 + |> Backing.lens.amount .~ 700 + ) + + self.vm.inputs.configureWith(project: project, rewardOrBacking: .init(reward)) + + let emissionCount = index + 1 + + self.pledgeButtonStyleType.assertValueCount(emissionCount) + self.pledgeButtonEnabled.assertValueCount(emissionCount) + self.pledgeButtonHidden.assertValueCount(emissionCount) + self.pledgeButtonTitleText.assertValueCount(emissionCount) + } + + self.pledgeButtonStyleType.assertValueCount(self.allRewards.count) + self.pledgeButtonEnabled.assertValueCount(self.allRewards.count) + self.pledgeButtonHidden.assertValueCount(self.allRewards.count) + self.pledgeButtonTitleText.assertValueCount(self.allRewards.count) + + self.pledgeButtonStyleType.assertValues([.black, .black, .black, .black, .black, .black, .black, .black]) + self.pledgeButtonEnabled.assertValues([true, true, true, true, true, true, true, true]) + self.pledgeButtonHidden.assertValues([false, false, false, false, false, false, false, false]) + self.pledgeButtonTitleText.assertValues([ + "View your pledge", + "View your pledge", + "View your pledge", + "View your pledge", + "View your pledge", + "View your pledge", + "View your pledge", + "View your pledge" + ]) + } + + func testNonLive_BackedProject_NonBackedReward() { + self.pledgeButtonStyleType.assertValueCount(0) + self.pledgeButtonEnabled.assertValueCount(0) + self.pledgeButtonHidden.assertValueCount(0) + self.pledgeButtonTitleText.assertValueCount(0) + + for (index, reward) in self.allRewards.enumerated() { + let project = Project.cosmicSurgery + |> Project.lens.state .~ .successful + |> Project.lens.personalization.isBacking .~ true + |> Project.lens.personalization.backing .~ ( + .template + |> Backing.lens.reward .~ Reward.otherReward + |> Backing.lens.rewardId .~ Reward.otherReward.id + |> Backing.lens.shippingAmount .~ 10 + |> Backing.lens.amount .~ 700 + ) + + self.vm.inputs.configureWith(project: project, rewardOrBacking: .init(reward)) + + let emissionCount = index + 1 + + self.pledgeButtonStyleType.assertValueCount(emissionCount) + self.pledgeButtonEnabled.assertValueCount(emissionCount) + self.pledgeButtonHidden.assertValueCount(emissionCount) + self.pledgeButtonTitleText.assertValueCount(emissionCount) + } + + self.pledgeButtonStyleType.assertValueCount(self.allRewards.count) + self.pledgeButtonEnabled.assertValueCount(self.allRewards.count) + self.pledgeButtonHidden.assertValueCount(self.allRewards.count) + self.pledgeButtonTitleText.assertValueCount(self.allRewards.count) + + self.pledgeButtonStyleType.assertValues([.none, .none, .none, .none, .none, .none, .none, .none]) + self.pledgeButtonEnabled.assertValues([false, false, false, false, false, false, false, false]) + self.pledgeButtonHidden.assertValues([true, true, true, true, true, true, true, true]) + self.pledgeButtonTitleText.assertValues([nil, nil, nil, nil, nil, nil, nil, nil]) + } + + func testNonLive_NonBackedProject() { + self.pledgeButtonStyleType.assertValueCount(0) + self.pledgeButtonEnabled.assertValueCount(0) + self.pledgeButtonHidden.assertValueCount(0) + self.pledgeButtonTitleText.assertValueCount(0) + + for (index, reward) in self.allRewards.enumerated() { + let project = Project.cosmicSurgery + |> Project.lens.state .~ .successful + |> Project.lens.personalization.isBacking .~ false + + self.vm.inputs.configureWith(project: project, rewardOrBacking: .init(reward)) + + let emissionCount = index + 1 + + self.pledgeButtonStyleType.assertValueCount(emissionCount) + self.pledgeButtonEnabled.assertValueCount(emissionCount) + self.pledgeButtonHidden.assertValueCount(emissionCount) + self.pledgeButtonTitleText.assertValueCount(emissionCount) + } + + self.pledgeButtonStyleType.assertValueCount(self.allRewards.count) + self.pledgeButtonEnabled.assertValueCount(self.allRewards.count) + self.pledgeButtonHidden.assertValueCount(self.allRewards.count) + self.pledgeButtonTitleText.assertValueCount(self.allRewards.count) + + self.pledgeButtonStyleType.assertValues([.none, .none, .none, .none, .none, .none, .none, .none]) + self.pledgeButtonEnabled.assertValues([false, false, false, false, false, false, false, false]) + self.pledgeButtonHidden.assertValues([true, true, true, true, true, true, true, true]) + self.pledgeButtonTitleText.assertValues([nil, nil, nil, nil, nil, nil, nil, nil]) + } + + func testLive_BackedProject_BackedReward_Errored() { + // exclude reward states we can't get to + let rewards = [ + availableLimitedReward, + availableTimebasedReward, + availableLimitedTimebasedReward, + availableNonLimitedReward, + Reward.noReward + ] + + self.pledgeButtonStyleType.assertValueCount(0) + self.pledgeButtonEnabled.assertValueCount(0) + self.pledgeButtonHidden.assertValueCount(0) + self.pledgeButtonTitleText.assertValueCount(0) + + for (index, reward) in rewards.enumerated() { + let project = Project.cosmicSurgery + |> Project.lens.state .~ .live + |> Project.lens.personalization.isBacking .~ true + |> Project.lens.personalization.backing .~ ( + .template + |> Backing.lens.reward .~ reward + |> Backing.lens.rewardId .~ reward.id + |> Backing.lens.shippingAmount .~ 10 + |> Backing.lens.amount .~ 700 + |> Backing.lens.status .~ .errored + ) + + self.vm.inputs.configureWith(project: project, rewardOrBacking: .init(reward)) + + let emissionCount = index + 1 + + self.pledgeButtonStyleType.assertValueCount(emissionCount) + self.pledgeButtonEnabled.assertValueCount(emissionCount) + self.pledgeButtonHidden.assertValueCount(emissionCount) + self.pledgeButtonTitleText.assertValueCount(emissionCount) + } + + self.pledgeButtonStyleType.assertValueCount(rewards.count) + self.pledgeButtonEnabled.assertValueCount(rewards.count) + self.pledgeButtonHidden.assertValueCount(rewards.count) + self.pledgeButtonTitleText.assertValueCount(rewards.count) + + self.pledgeButtonStyleType.assertValues([.apricot, .apricot, .apricot, .apricot, .apricot]) + self.pledgeButtonEnabled.assertValues([true, true, true, true, true]) + self.pledgeButtonHidden.assertValues([false, false, false, false, false]) + self.pledgeButtonTitleText.assertValues([ + "Fix your payment method", + "Fix your payment method", + "Fix your payment method", + "Fix your payment method", + "Fix your payment method" + ]) + } + + func testLive_BackedProject_NonBackedReward_Errored() { + self.pledgeButtonStyleType.assertValueCount(0) + self.pledgeButtonEnabled.assertValueCount(0) + self.pledgeButtonHidden.assertValueCount(0) + self.pledgeButtonTitleText.assertValueCount(0) + + for (index, reward) in self.allRewards.enumerated() { + let project = Project.cosmicSurgery + |> Project.lens.state .~ .live + |> Project.lens.personalization.isBacking .~ true + |> Project.lens.personalization.backing .~ ( + .template + |> Backing.lens.reward .~ Reward.otherReward + |> Backing.lens.rewardId .~ Reward.otherReward.id + |> Backing.lens.shippingAmount .~ 10 + |> Backing.lens.amount .~ 700 + |> Backing.lens.status .~ .errored + ) + + self.vm.inputs.configureWith(project: project, rewardOrBacking: .init(reward)) + + let emissionCount = index + 1 + + self.pledgeButtonStyleType.assertValueCount(emissionCount) + self.pledgeButtonEnabled.assertValueCount(emissionCount) + self.pledgeButtonHidden.assertValueCount(emissionCount) + self.pledgeButtonTitleText.assertValueCount(emissionCount) + } - self.vm.inputs.configureWith(project: project, rewardOrBacking: .left(reward)) + self.pledgeButtonStyleType.assertValueCount(self.allRewards.count) + self.pledgeButtonEnabled.assertValueCount(self.allRewards.count) + self.pledgeButtonHidden.assertValueCount(self.allRewards.count) + self.pledgeButtonTitleText.assertValueCount(self.allRewards.count) - self.pledgeButtonEnabled.assertValues([false]) + self.pledgeButtonStyleType.assertValues([.green, .green, .green, .green, .green, .green, .green, .green]) + self.pledgeButtonEnabled.assertValues([true, true, true, true, false, false, false, true]) + self.pledgeButtonHidden.assertValues([false, false, false, false, false, false, false, false]) + self.pledgeButtonTitleText.assertValues([ + "Select this reward instead", + "Select this reward instead", + "Select this reward instead", + "Select this reward instead", + "No longer available", + "No longer available", + "No longer available", + "Select this reward instead" + ]) } func testPledgeButtonTapped() { diff --git a/Library/ViewModels/RewardCardViewModel.swift b/Library/ViewModels/RewardCardViewModel.swift index 7d5aa94ff7..bbdab4e3c9 100644 --- a/Library/ViewModels/RewardCardViewModel.swift +++ b/Library/ViewModels/RewardCardViewModel.swift @@ -12,12 +12,18 @@ public protocol RewardCardViewModelOutputs { var conversionLabelHidden: Signal { get } var conversionLabelText: Signal { get } var descriptionLabelText: Signal { get } - var items: Signal<[String], Never> { get } var includedItemsStackViewHidden: Signal { get } + var items: Signal<[String], Never> { get } + var pillCollectionViewHidden: Signal { get } + var reloadPills: Signal<[String], Never> { get } var rewardMinimumLabelText: Signal { get } var rewardSelected: Signal { get } var rewardTitleLabelHidden: Signal { get } var rewardTitleLabelText: Signal { get } + var stateIconImageName: Signal { get } + var stateIconImageTintColor: Signal { get } + var stateIconImageViewContainerBackgroundColor: Signal { get } + var stateIconImageViewContainerHidden: Signal { get } } public protocol RewardCardViewModelType { @@ -101,6 +107,19 @@ public final class RewardCardViewModel: RewardCardViewModelType, RewardCardViewM } } + self.reloadPills = projectAndReward.map(pillStrings(project:reward:)) + self.pillCollectionViewHidden = self.reloadPills.map { $0.isEmpty } + + let stateIconImageName = projectAndReward.map(stateIconImageName(project:reward:)) + let stateIconImageColor = projectAndReward.map(stateIconImageColor(project:reward:)) + + self.stateIconImageName = stateIconImageName.skipNil() + self.stateIconImageTintColor = stateIconImageColor.skipNil() + self.stateIconImageViewContainerBackgroundColor = stateIconImageColor + .skipNil() + .map { $0.withAlphaComponent(0.06) } + self.stateIconImageViewContainerHidden = stateIconImageName.map(isNil) + self.rewardSelected = reward .takeWhen(self.rewardCardTappedProperty.signal) .map { $0.id } @@ -124,10 +143,16 @@ public final class RewardCardViewModel: RewardCardViewModelType, RewardCardViewM public let descriptionLabelText: Signal public let items: Signal<[String], Never> public let includedItemsStackViewHidden: Signal + public let pillCollectionViewHidden: Signal + public let reloadPills: Signal<[String], Never> public let rewardMinimumLabelText: Signal public let rewardSelected: Signal public let rewardTitleLabelHidden: Signal public let rewardTitleLabelText: Signal + public let stateIconImageName: Signal + public let stateIconImageTintColor: Signal + public let stateIconImageViewContainerBackgroundColor: Signal + public let stateIconImageViewContainerHidden: Signal public var inputs: RewardCardViewModelInputs { return self } public var outputs: RewardCardViewModelOutputs { return self } @@ -152,10 +177,53 @@ private func backingReward(fromProject project: Project) -> Reward? { private func rewardTitle(project: Project, reward: Reward) -> String { guard project.personalization.isBacking == true else { - return reward.isNoReward - ? Strings.Make_a_pledge_without_a_reward() - : (reward.title ?? "") + return reward.isNoReward ? Strings.Make_a_pledge_without_a_reward() : reward.title.coalesceWith("") + } + + if reward.isNoReward { + if userIsBacking(reward: reward, inProject: project) { + return Strings.Thank_you_for_supporting_this_project() + } + + return Strings.Make_a_pledge_without_a_reward() + } + + return reward.title.coalesceWith("") +} + +private func pillStrings(project: Project, reward: Reward) -> [String] { + var pillStrings: [String] = [] + + if let endsAt = reward.endsAt, project.state == .live, endsAt > 0, + endsAt >= AppEnvironment.current.dateType.init().timeIntervalSince1970 { + let (time, unit) = Format.duration( + secondsInUTC: min(endsAt, project.dates.deadline), + abbreviate: true, + useToGo: false + ) + + pillStrings.append(Strings.Time_left_left(time_left: time + " " + unit)) + } + + if let remaining = reward.remaining, reward.limit != nil, project.state == .live { + pillStrings.append(Strings.Left_count_left(left_count: remaining)) + } + + return pillStrings +} + +private func stateIconImageColor(project: Project, reward: Reward) -> UIColor? { + guard userIsBacking(reward: reward, inProject: project) else { return nil } + + if project.state == .live { + return project.personalization.backing?.status == .errored ? .ksr_apricot_500 : .ksr_blue_500 } - return reward.title ?? Strings.Thank_you_for_supporting_this_project() + return .ksr_soft_black +} + +private func stateIconImageName(project: Project, reward: Reward) -> String? { + guard userIsBacking(reward: reward, inProject: project) else { return nil } + + return project.personalization.backing?.status == .errored ? "icon--alert" : "checkmark-reward" } diff --git a/Library/ViewModels/RewardCardViewModelTests.swift b/Library/ViewModels/RewardCardViewModelTests.swift index 8594f05ebc..8e71802d2f 100644 --- a/Library/ViewModels/RewardCardViewModelTests.swift +++ b/Library/ViewModels/RewardCardViewModelTests.swift @@ -1,3 +1,4 @@ +import Foundation @testable import KsApi @testable import Library import Prelude @@ -15,12 +16,16 @@ final class RewardCardViewModelTests: TestCase { private let descriptionLabelText = TestObserver() private let includedItemsStackViewHidden = TestObserver() private let items = TestObserver<[String], Never>() - private let pledgeButtonEnabled = TestObserver() - private let pledgeButtonTitleText = TestObserver() + private let pillCollectionViewHidden = TestObserver() + private let reloadPills = TestObserver<[String], Never>() private let rewardMinimumLabelText = TestObserver() private let rewardSelected = TestObserver() private let rewardTitleLabelHidden = TestObserver() private let rewardTitleLabelText = TestObserver() + private let stateIconImageName = TestObserver() + private let stateIconImageTintColor = TestObserver() + private let stateIconImageViewContainerBackgroundColor = TestObserver() + private let stateIconImageViewContainerHidden = TestObserver() override func setUp() { super.setUp() @@ -29,12 +34,19 @@ final class RewardCardViewModelTests: TestCase { self.vm.outputs.conversionLabelHidden.observe(self.conversionLabelHidden.observer) self.vm.outputs.conversionLabelText.observe(self.conversionLabelText.observer) self.vm.outputs.descriptionLabelText.observe(self.descriptionLabelText.observer) - self.vm.outputs.items.observe(self.items.observer) self.vm.outputs.includedItemsStackViewHidden.observe(self.includedItemsStackViewHidden.observer) + self.vm.outputs.items.observe(self.items.observer) + self.vm.outputs.pillCollectionViewHidden.observe(self.pillCollectionViewHidden.observer) + self.vm.outputs.reloadPills.observe(self.reloadPills.observer) self.vm.outputs.rewardMinimumLabelText.observe(self.rewardMinimumLabelText.observer) self.vm.outputs.rewardSelected.observe(self.rewardSelected.observer) self.vm.outputs.rewardTitleLabelHidden.observe(self.rewardTitleLabelHidden.observer) self.vm.outputs.rewardTitleLabelText.observe(self.rewardTitleLabelText.observer) + self.vm.outputs.stateIconImageName.observe(self.stateIconImageName.observer) + self.vm.outputs.stateIconImageTintColor.observe(self.stateIconImageTintColor.observer) + self.vm.outputs.stateIconImageViewContainerBackgroundColor + .observe(self.stateIconImageViewContainerBackgroundColor.observer) + self.vm.outputs.stateIconImageViewContainerHidden.observe(self.stateIconImageViewContainerHidden.observer) } // MARK: - Reward Title @@ -79,6 +91,30 @@ final class RewardCardViewModelTests: TestCase { self.rewardTitleLabelText.assertValues(["Make a pledge without a reward"]) } + func testTitleLabel_BackedNoReward() { + let reward = Reward.noReward + + let project = Project.cosmicSurgery + |> Project.lens.state .~ .live + |> Project.lens.personalization.isBacking .~ true + |> Project.lens.personalization.backing .~ ( + .template + |> Backing.lens.reward .~ reward + |> Backing.lens.rewardId .~ reward.id + |> Backing.lens.amount .~ 700 + ) + + self.vm.inputs.configureWith( + project: project, + rewardOrBacking: .left(reward) + ) + + self.rewardTitleLabelHidden.assertValues([false]) + self.rewardTitleLabelText.assertValues([ + "Thank you for supporting this project." + ]) + } + // MARK: - Reward Minimum func testMinimumLabel_US_Project_US_UserLocation() { @@ -246,7 +282,7 @@ final class RewardCardViewModelTests: TestCase { self.includedItemsStackViewHidden.assertValues([true]) } - // MARK: - Description Label + // MARK: Description Label func testDescriptionLabel() { let project = Project.template @@ -607,4 +643,246 @@ final class RewardCardViewModelTests: TestCase { self.cardUserInteractionIsEnabled.assertValues([false]) } + + // MARK: - Pills + + func testPillsLimitedReward() { + self.pillCollectionViewHidden.assertValueCount(0) + self.reloadPills.assertValueCount(0) + + let reward = Reward.postcards + |> Reward.lens.limit .~ 100 + |> Reward.lens.remaining .~ 25 + + self.vm.inputs.configureWith(project: .template, rewardOrBacking: .left(reward)) + + self.pillCollectionViewHidden.assertValues([false]) + self.reloadPills.assertValues([ + ["25 left"] + ]) + } + + func testPillsTimebasedReward_24hrs() { + self.pillCollectionViewHidden.assertValueCount(0) + self.reloadPills.assertValueCount(0) + + let reward = Reward.postcards + |> Reward.lens.limit .~ nil + |> Reward.lens.remaining .~ nil + |> Reward.lens.endsAt .~ (MockDate().timeIntervalSince1970 + 60.0 * 60.0 * 24.0) + + self.vm.inputs.configureWith(project: .template, rewardOrBacking: .left(reward)) + + self.pillCollectionViewHidden.assertValues([false]) + self.reloadPills.assertValues([ + ["24 hrs left"] + ]) + } + + func testPillsTimebasedReward_4days() { + self.pillCollectionViewHidden.assertValueCount(0) + self.reloadPills.assertValueCount(0) + + let date = AppEnvironment.current.calendar.date(byAdding: DateComponents(day: 4), to: MockDate().date) + + let reward = Reward.postcards + |> Reward.lens.limit .~ nil + |> Reward.lens.remaining .~ nil + |> Reward.lens.endsAt .~ date?.timeIntervalSince1970 + + self.vm.inputs.configureWith(project: .template, rewardOrBacking: .left(reward)) + + self.pillCollectionViewHidden.assertValues([false]) + self.reloadPills.assertValues([ + ["4 days left"] + ]) + } + + func testPillsTimebasedAndLimitedReward() { + self.pillCollectionViewHidden.assertValueCount(0) + self.reloadPills.assertValueCount(0) + + let date = AppEnvironment.current.calendar.date(byAdding: DateComponents(day: 4), to: MockDate().date) + + let reward = Reward.postcards + |> Reward.lens.limit .~ 100 + |> Reward.lens.remaining .~ 75 + |> Reward.lens.endsAt .~ date?.timeIntervalSince1970 + + self.vm.inputs.configureWith(project: .template, rewardOrBacking: .left(reward)) + + self.pillCollectionViewHidden.assertValues([false]) + self.reloadPills.assertValues([ + ["4 days left", "75 left"] + ]) + } + + func testPillsTimebasedAndLimitedReward_NonLiveProject() { + self.pillCollectionViewHidden.assertValueCount(0) + self.reloadPills.assertValueCount(0) + + let date = AppEnvironment.current.calendar.date(byAdding: DateComponents(day: 4), to: MockDate().date) + + let project = Project.template + |> Project.lens.state .~ .successful + + let reward = Reward.postcards + |> Reward.lens.limit .~ 100 + |> Reward.lens.remaining .~ 75 + |> Reward.lens.endsAt .~ date?.timeIntervalSince1970 + + self.vm.inputs.configureWith(project: project, rewardOrBacking: .left(reward)) + + self.pillCollectionViewHidden.assertValues([true]) + self.reloadPills.assertValues([[]]) + } + + func testPillsTimebasedAndLimitedReward_Unavailable() { + self.pillCollectionViewHidden.assertValueCount(0) + self.reloadPills.assertValueCount(0) + + let reward = Reward.postcards + |> Reward.lens.limit .~ 100 + |> Reward.lens.remaining .~ 0 + |> Reward.lens.endsAt .~ (MockDate().date.timeIntervalSince1970 - 1) + + self.vm.inputs.configureWith(project: .template, rewardOrBacking: .left(reward)) + + self.pillCollectionViewHidden.assertValues([false]) + self.reloadPills.assertValues([["0 left"]]) + } + + func testPillsNonLimitedReward() { + self.pillCollectionViewHidden.assertValueCount(0) + self.reloadPills.assertValueCount(0) + + let reward = Reward.postcards + |> Reward.lens.limit .~ nil + |> Reward.lens.endsAt .~ nil + + self.vm.inputs.configureWith(project: .template, rewardOrBacking: .left(reward)) + + self.pillCollectionViewHidden.assertValues([true]) + self.reloadPills.assertValues([[]]) + } + + // State Icon Image + + func testStateIconImage_BackedReward() { + self.stateIconImageName.assertValueCount(0) + self.stateIconImageTintColor.assertValueCount(0) + self.stateIconImageViewContainerBackgroundColor.assertValueCount(0) + self.stateIconImageViewContainerHidden.assertValueCount(0) + + let reward = Reward.postcards + + let project = Project.cosmicSurgery + |> Project.lens.state .~ .live + |> Project.lens.personalization.isBacking .~ true + |> Project.lens.personalization.backing .~ ( + .template + |> Backing.lens.reward .~ reward + |> Backing.lens.rewardId .~ reward.id + |> Backing.lens.shippingAmount .~ 10 + |> Backing.lens.amount .~ 700 + ) + + self.vm.inputs.configureWith( + project: project, + rewardOrBacking: .left(reward) + ) + + self.stateIconImageName.assertValues(["checkmark-reward"]) + self.stateIconImageTintColor.assertValues([.ksr_blue_500]) + self.stateIconImageViewContainerBackgroundColor.assertValues( + [UIColor.ksr_blue_500.withAlphaComponent(0.06)] + ) + self.stateIconImageViewContainerHidden.assertValues([false]) + } + + func testStateIconImage_BackedOtherReward() { + self.stateIconImageName.assertValueCount(0) + self.stateIconImageTintColor.assertValueCount(0) + self.stateIconImageViewContainerBackgroundColor.assertValueCount(0) + self.stateIconImageViewContainerHidden.assertValueCount(0) + + let reward = Reward.postcards + + let project = Project.cosmicSurgery + |> Project.lens.state .~ .live + |> Project.lens.personalization.isBacking .~ true + |> Project.lens.personalization.backing .~ ( + .template + |> Backing.lens.reward .~ Reward.otherReward + |> Backing.lens.rewardId .~ Reward.otherReward.id + |> Backing.lens.shippingAmount .~ 10 + |> Backing.lens.amount .~ 700 + ) + + self.vm.inputs.configureWith( + project: project, + rewardOrBacking: .left(reward) + ) + + self.stateIconImageName.assertValues([]) + self.stateIconImageTintColor.assertValues([]) + self.stateIconImageViewContainerBackgroundColor.assertValues([]) + self.stateIconImageViewContainerHidden.assertValues([true]) + } + + func testStateIconImage_BackedRewardErrored() { + self.stateIconImageName.assertValueCount(0) + self.stateIconImageTintColor.assertValueCount(0) + self.stateIconImageViewContainerBackgroundColor.assertValueCount(0) + self.stateIconImageViewContainerHidden.assertValueCount(0) + + let reward = Reward.postcards + + let project = Project.cosmicSurgery + |> Project.lens.state .~ .live + |> Project.lens.personalization.isBacking .~ true + |> Project.lens.personalization.backing .~ ( + .template + |> Backing.lens.status .~ .errored + |> Backing.lens.reward .~ reward + |> Backing.lens.rewardId .~ reward.id + |> Backing.lens.shippingAmount .~ 10 + |> Backing.lens.amount .~ 700 + ) + + self.vm.inputs.configureWith( + project: project, + rewardOrBacking: .left(reward) + ) + + self.stateIconImageName.assertValues(["icon--alert"]) + self.stateIconImageTintColor.assertValues([.ksr_apricot_500]) + self.stateIconImageViewContainerBackgroundColor.assertValues( + [UIColor.ksr_apricot_500.withAlphaComponent(0.06)] + ) + self.stateIconImageViewContainerHidden.assertValues([false]) + } + + func testStateIconImage_NonBacked() { + self.stateIconImageName.assertValueCount(0) + self.stateIconImageTintColor.assertValueCount(0) + self.stateIconImageViewContainerBackgroundColor.assertValueCount(0) + self.stateIconImageViewContainerHidden.assertValueCount(0) + + let reward = Reward.postcards + + let project = Project.cosmicSurgery + |> Project.lens.state .~ .live + |> Project.lens.personalization.isBacking .~ false + + self.vm.inputs.configureWith( + project: project, + rewardOrBacking: .left(reward) + ) + + self.stateIconImageName.assertValues([]) + self.stateIconImageTintColor.assertValues([]) + self.stateIconImageViewContainerBackgroundColor.assertValues([]) + self.stateIconImageViewContainerHidden.assertValues([true]) + } } diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..383d9ce58d Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..d68f7455e5 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..35a2a4e7ae Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..005e11d7cc Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_Errored_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_Errored_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..0d7d89abd1 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_Errored_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_Errored_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_Errored_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..a4402035ae Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_Errored_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_Errored_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_Errored_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..7f7c7ceb5d Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_Errored_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_Errored_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_Errored_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..18168c3374 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_Errored_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_Errored_NoReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_Errored_NoReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..fbe4276c34 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_Errored_NoReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_NoReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_NoReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..5ec26d4790 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_NoReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..0c0937df1c Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..0c0937df1c Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..35a2a4e7ae Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_BackedReward_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..33870e1354 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..c760ce9233 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..979bf9b63e Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..ea9d4b0eef Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..33870e1354 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..c760ce9233 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..979bf9b63e Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..ea9d4b0eef Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_NoReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_NoReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..226904c74a Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_NoReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..32cbb0e720 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..32cbb0e720 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..26819f59b6 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_Errored_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_NoReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_NoReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..226904c74a Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_NoReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..32cbb0e720 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..32cbb0e720 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..26819f59b6 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_BackedProject_NonBackedReward_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..dcd0d22770 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..fcfa7aa02c Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..a276c78f9f Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..6880e7d4b2 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_NoReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_NoReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..3ad1784e32 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_NoReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..32cbb0e720 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..32cbb0e720 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..26819f59b6 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedIn_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..dcd0d22770 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..fcfa7aa02c Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..a276c78f9f Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..6880e7d4b2 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_NoReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_NoReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..3ad1784e32 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_NoReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..32cbb0e720 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..32cbb0e720 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..26819f59b6 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testLive_NonBackedProject_LoggedOut_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..285da4976d Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..285da4976d Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..285da4976d Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..285da4976d Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_NoReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_NoReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..d3d930259f Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_NoReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..285da4976d Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..285da4976d Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..285da4976d Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_BackedReward_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..d09cdd05f1 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..d09cdd05f1 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..d09cdd05f1 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..d09cdd05f1 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_NoReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_NoReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..9381c5571d Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_NoReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..d09cdd05f1 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..d09cdd05f1 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..d09cdd05f1 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_BackedProject_NonBackedReward_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..d09cdd05f1 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_AvailableLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..d09cdd05f1 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_AvailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..d09cdd05f1 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_AvailableNonLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..d09cdd05f1 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_AvailableTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_NoReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_NoReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..9381c5571d Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_NoReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..d09cdd05f1 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_UnavailableLimitedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..d09cdd05f1 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_UnavailableLimitedTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png new file mode 100644 index 0000000000..d09cdd05f1 Binary files /dev/null and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardCardContainerViewTests/testNonLive_NonBackedProject_UnavailableTimebasedReward_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_de_device_pad@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_de_device_pad@2x.png index fd3ad049e0..02377f7e04 100644 Binary files a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_de_device_pad@2x.png and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_de_device_pad@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_de_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_de_device_phone4_7inch@2x.png index 0fedaeef9a..b4cdd7cd22 100644 Binary files a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_de_device_phone4_7inch@2x.png and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_de_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_de_device_phone5_8inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_de_device_phone5_8inch@2x.png index 0fedaeef9a..b4cdd7cd22 100644 Binary files a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_de_device_phone5_8inch@2x.png and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_de_device_phone5_8inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_en_device_pad@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_en_device_pad@2x.png index 9a1ca053ff..257855c420 100644 Binary files a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_en_device_pad@2x.png and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_en_device_pad@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_en_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_en_device_phone4_7inch@2x.png index 93b3e313cc..a1e8ca5ecb 100644 Binary files a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_en_device_phone4_7inch@2x.png and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_en_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_en_device_phone5_8inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_en_device_phone5_8inch@2x.png index 93b3e313cc..a1e8ca5ecb 100644 Binary files a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_en_device_phone5_8inch@2x.png and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_en_device_phone5_8inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_es_device_pad@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_es_device_pad@2x.png index cc76f6f00e..79dbcd6858 100644 Binary files a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_es_device_pad@2x.png and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_es_device_pad@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_es_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_es_device_phone4_7inch@2x.png index 0851c42222..43cc551edb 100644 Binary files a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_es_device_phone4_7inch@2x.png and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_es_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_es_device_phone5_8inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_es_device_phone5_8inch@2x.png index 0851c42222..43cc551edb 100644 Binary files a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_es_device_phone5_8inch@2x.png and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_es_device_phone5_8inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_fr_device_pad@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_fr_device_pad@2x.png index 06eff17fd0..e5f196aecb 100644 Binary files a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_fr_device_pad@2x.png and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_fr_device_pad@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_fr_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_fr_device_phone4_7inch@2x.png index ed22c17ac0..4ec74b5533 100644 Binary files a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_fr_device_phone4_7inch@2x.png and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_fr_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_fr_device_phone5_8inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_fr_device_phone5_8inch@2x.png index ed22c17ac0..4ec74b5533 100644 Binary files a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_fr_device_phone5_8inch@2x.png and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_fr_device_phone5_8inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_ja_device_pad@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_ja_device_pad@2x.png index 511ba5f2c8..5837e2d478 100644 Binary files a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_ja_device_pad@2x.png and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_ja_device_pad@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_ja_device_phone4_7inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_ja_device_phone4_7inch@2x.png index d4c97cf3ae..334027de2e 100644 Binary files a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_ja_device_phone4_7inch@2x.png and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_ja_device_phone4_7inch@2x.png differ diff --git a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_ja_device_phone5_8inch@2x.png b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_ja_device_phone5_8inch@2x.png index d4c97cf3ae..334027de2e 100644 Binary files a/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_ja_device_phone5_8inch@2x.png and b/Screenshots/_64/Kickstarter_Framework_iOSTests.RewardsCollectionViewControllerTests/testRewards_NonBacker_LiveProject_lang_ja_device_phone5_8inch@2x.png differ