Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NT-206] Reward received toggle business logic #866

Merged
merged 10 commits into from
Oct 3, 2019
20 changes: 11 additions & 9 deletions Kickstarter-iOS/Views/Controllers/ManagePledgeViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import UIKit
final class ManagePledgeViewController: UIViewController {
// MARK: - Properties

private let viewModel: ManagePledgeViewModelType = ManagePledgeViewModel()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've moved the viewModel to the top of Properties section. This is consistent with the rest of the codebase and makes it easier to glance at the same place where we would in other VC


private lazy var closeButton: UIBarButtonItem = {
UIBarButtonItem(
image: UIImage(named: "icon--cross"),
Expand Down Expand Up @@ -44,15 +46,6 @@ final class ManagePledgeViewController: UIViewController {
|> \.translatesAutoresizingMaskIntoConstraints .~ false
}()

private let viewModel: ManagePledgeViewModelType = ManagePledgeViewModel()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've mostly used two step configuration

  1. Instantiate
  2. Configure

So I've gotten rid of this because it was effectively introducing pattern we've been trying to move away from and making the configureWith function obsolete.


static func instantiate(with project: Project, reward: Reward) -> ManagePledgeViewController {
let manageViewPledgeVC = ManagePledgeViewController.instantiate()
manageViewPledgeVC.viewModel.inputs.configureWith(project, reward: reward)

return manageViewPledgeVC
}

// MARK: - Lifecycle

override func viewDidLoad() {
Expand Down Expand Up @@ -95,6 +88,9 @@ final class ManagePledgeViewController: UIViewController {
override func bindViewModel() {
super.bindViewModel()

self.rewardReceivedViewController.view.rac.hidden =
self.viewModel.outputs.rewardReceivedViewControllerViewIsHidden

self.viewModel.outputs.title
.observeForUI()
.observeValues { [weak self] title in
Expand All @@ -115,6 +111,12 @@ final class ManagePledgeViewController: UIViewController {
self?.pledgeSummaryView.configureWith(project)
}

self.viewModel.outputs.configureRewardReceivedWithProject
.observeForControllerAction()
.observeValues { [weak self] project in
self?.rewardReceivedViewController.configureWith(project: project)
}

self.viewModel.outputs.configureRewardSummaryView
.observeForUI()
.observeValues { _ in }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,36 @@
import Library
import KsApi
import Prelude
import UIKit

final class ManageViewPledgeRewardReceivedViewController: ToggleViewController {
// MARK: - Properties

private let viewModel: ManageViewPledgeRewardReceivedViewModelType
= ManageViewPledgeRewardReceivedViewModel()

// MARK: - Lifecycle

override func viewDidLoad() {
super.viewDidLoad()

self.toggle.addTarget(self, action: #selector(toggleValueDidChange(_:)), for: .valueChanged)

self.viewModel.inputs.viewDidLoad()
}

// MARK: - Actions

@objc private func toggleValueDidChange(_ toggle: UISwitch) {
self.viewModel.inputs.rewardReceivedToggleTapped(isOn: toggle.isOn)
}

// MARK: - Configuration

public func configureWith(project: Project) {
self.viewModel.inputs.configureWith(project)
}

// MARK: - Styles

override func bindStyles() {
Expand All @@ -15,4 +43,16 @@ final class ManageViewPledgeRewardReceivedViewController: ToggleViewController {
_ = self.toggle
|> checkoutSwitchControlStyle
}

// MARK: - View model

override func bindViewModel() {
super.bindViewModel()

self.viewModel.outputs.rewardReceived
.observeForUI()
.observeValues { [weak self] isOn in
self?.toggle.isOn = isOn
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't you add a RAC binding for this? self.toggle.rac.on?

Copy link
Contributor Author

@dusi dusi Oct 3, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, got tripped by it being called on not isOn ... yeah I can use it!

}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
@testable import Kickstarter_Framework
@testable import KsApi
@testable import Library
import Prelude
import UIKit

final class ManageViewPledgeRewardReceivedViewControllerTests: TestCase {
Expand All @@ -17,20 +19,40 @@ final class ManageViewPledgeRewardReceivedViewControllerTests: TestCase {
super.tearDown()
}

func testView() {
func testView_Toggle_Off() {
let devices = [Device.phone4_7inch, Device.phone5_8inch, Device.pad]
let toggleStates = [true, false]
combos([Language.en], devices, toggleStates).forEach { language, device, toggleState in
combos([Language.en], devices).forEach { language, device in
withEnvironment(language: language) {
let controller = ManageViewPledgeRewardReceivedViewController.instantiate()
controller.toggle.setOn(toggleState, animated: false)
controller.configureWith(project: .template)

let (parent, _) = traitControllers(device: device, orientation: .portrait, child: controller)

parent.view.frame.size.height = 60

FBSnapshotVerifyView(
parent.view, identifier: "lang_\(language)_device_\(device)_toggle_\(toggleState)"
parent.view, identifier: "lang_\(language)_device_\(device)"
)
}
}
}

func testView_Toggle_On() {
let devices = [Device.phone4_7inch, Device.phone5_8inch, Device.pad]
combos([Language.en], devices).forEach { language, device in
withEnvironment(language: language) {
let project = Project.template
|> Project.lens.personalization .. Project.Personalization.lens.backing .~ .template

let controller = ManageViewPledgeRewardReceivedViewController.instantiate()
controller.configureWith(project: project)

let (parent, _) = traitControllers(device: device, orientation: .portrait, child: controller)

parent.view.frame.size.height = 60

FBSnapshotVerifyView(
parent.view, identifier: "lang_\(language)_device_\(device)"
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,14 +207,17 @@ public final class ProjectPamphletViewController: UIViewController {
}

private func goToManageViewPledge(project: Project, reward: Reward, refTag _: RefTag?) {
let managePledgeViewController = ManagePledgeViewController.instantiate(with: project, reward: reward)
let vc = ManagePledgeViewController.instantiate()
vc.configureWith(project: project, reward: reward)

let nc = RewardPledgeNavigationController(rootViewController: vc)

let nav = RewardPledgeNavigationController(rootViewController: managePledgeViewController)
if AppEnvironment.current.device.userInterfaceIdiom == .pad {
_ = nav
_ = nc
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The diff would probably be small with less renaming here 😬

|> \.modalPresentationStyle .~ .formSheet
}
self.present(nav, animated: true)

self.present(nc, animated: true)
}

private func goToDeprecatedManagePledge(project: Project, reward: Reward, refTag _: RefTag?) {
Expand Down
18 changes: 12 additions & 6 deletions Kickstarter.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@
3767EDB122CFFF2B0088E8E4 /* ShippingRulesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3767EDB022CFFF2B0088E8E4 /* ShippingRulesViewModel.swift */; };
3767EDB322CFFF380088E8E4 /* ShippingRulesViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3767EDB222CFFF380088E8E4 /* ShippingRulesViewModelTests.swift */; };
3772A4C6229C9E2000EDDC6F /* String+Attributed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3772A4C5229C9E2000EDDC6F /* String+Attributed.swift */; };
3777F2F72343C7900030BEF5 /* ManageViewPledgeRewardReceivedViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3777F2F62343C7900030BEF5 /* ManageViewPledgeRewardReceivedViewModel.swift */; };
3777F2F92343C7AB0030BEF5 /* ManageViewPledgeRewardReceivedViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3777F2F82343C7AB0030BEF5 /* ManageViewPledgeRewardReceivedViewModelTests.swift */; };
3780C8622208F8C8002117D1 /* SettingsTextInputCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3780C8602208F8C1002117D1 /* SettingsTextInputCell.swift */; };
378CA24622C4449F004E3C86 /* CountryLenses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 378CA24522C4449F004E3C86 /* CountryLenses.swift */; };
379C00012242DAFF00F6F0C2 /* WebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379CFFF12242DAC400F6F0C2 /* WebViewController.swift */; };
Expand Down Expand Up @@ -309,10 +311,10 @@
8A072D3A230223B200BA1538 /* UIImage+Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A072D39230223B200BA1538 /* UIImage+Color.swift */; };
8A142EBD23354BFD00FB43AB /* AddNewCardIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A142EBC23354BFD00FB43AB /* AddNewCardIntent.swift */; };
8A23EF0822F11470001262E1 /* RewardCardContainerViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A23EF0722F11470001262E1 /* RewardCardContainerViewTests.swift */; };
8A73EAD9233B00A500FF9051 /* NSMutableAttributedString+SetFontKeepingTraits.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A73EAD8233B00A500FF9051 /* NSMutableAttributedString+SetFontKeepingTraits.swift */; };
8A73EADE233BE12D00FF9051 /* NSMutableAttributedString+SetFontKeepingTraitsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A73EADD233BE12D00FF9051 /* NSMutableAttributedString+SetFontKeepingTraitsTests.swift */; };
8A73EACF2339528000FF9051 /* PledgeCreditCardViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A73EACE2339528000FF9051 /* PledgeCreditCardViewModel.swift */; };
8A73EAD12339732900FF9051 /* PledgeCreditCardViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A73EAD02339732900FF9051 /* PledgeCreditCardViewModelTests.swift */; };
8A73EAD9233B00A500FF9051 /* NSMutableAttributedString+SetFontKeepingTraits.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A73EAD8233B00A500FF9051 /* NSMutableAttributedString+SetFontKeepingTraits.swift */; };
8A73EADE233BE12D00FF9051 /* NSMutableAttributedString+SetFontKeepingTraitsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A73EADD233BE12D00FF9051 /* NSMutableAttributedString+SetFontKeepingTraitsTests.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 */; };
Expand Down Expand Up @@ -1478,6 +1480,8 @@
3767EDB022CFFF2B0088E8E4 /* ShippingRulesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingRulesViewModel.swift; sourceTree = "<group>"; };
3767EDB222CFFF380088E8E4 /* ShippingRulesViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingRulesViewModelTests.swift; sourceTree = "<group>"; };
3772A4C5229C9E2000EDDC6F /* String+Attributed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Attributed.swift"; sourceTree = "<group>"; };
3777F2F62343C7900030BEF5 /* ManageViewPledgeRewardReceivedViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManageViewPledgeRewardReceivedViewModel.swift; sourceTree = "<group>"; };
3777F2F82343C7AB0030BEF5 /* ManageViewPledgeRewardReceivedViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManageViewPledgeRewardReceivedViewModelTests.swift; sourceTree = "<group>"; };
3780C8602208F8C1002117D1 /* SettingsTextInputCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTextInputCell.swift; sourceTree = "<group>"; };
378CA24522C4449F004E3C86 /* CountryLenses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CountryLenses.swift; sourceTree = "<group>"; };
379CFFEA2242DAC200F6F0C2 /* UIImageView+URL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImageView+URL.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1674,10 +1678,10 @@
8A072D39230223B200BA1538 /* UIImage+Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Color.swift"; sourceTree = "<group>"; };
8A142EBC23354BFD00FB43AB /* AddNewCardIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddNewCardIntent.swift; sourceTree = "<group>"; };
8A23EF0722F11470001262E1 /* RewardCardContainerViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RewardCardContainerViewTests.swift; sourceTree = "<group>"; };
8A73EAD8233B00A500FF9051 /* NSMutableAttributedString+SetFontKeepingTraits.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSMutableAttributedString+SetFontKeepingTraits.swift"; sourceTree = "<group>"; };
8A73EADD233BE12D00FF9051 /* NSMutableAttributedString+SetFontKeepingTraitsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSMutableAttributedString+SetFontKeepingTraitsTests.swift"; sourceTree = "<group>"; };
8A73EACE2339528000FF9051 /* PledgeCreditCardViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PledgeCreditCardViewModel.swift; sourceTree = "<group>"; };
8A73EAD02339732900FF9051 /* PledgeCreditCardViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PledgeCreditCardViewModelTests.swift; sourceTree = "<group>"; };
8A73EAD8233B00A500FF9051 /* NSMutableAttributedString+SetFontKeepingTraits.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSMutableAttributedString+SetFontKeepingTraits.swift"; sourceTree = "<group>"; };
8A73EADD233BE12D00FF9051 /* NSMutableAttributedString+SetFontKeepingTraitsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSMutableAttributedString+SetFontKeepingTraitsTests.swift"; sourceTree = "<group>"; };
8A8099E922E213F100373E66 /* RewardCardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RewardCardView.swift; sourceTree = "<group>"; };
8A8099EA22E213F100373E66 /* RewardCardContainerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RewardCardContainerView.swift; sourceTree = "<group>"; };
8A8099ED22E2142C00373E66 /* RewardCardViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RewardCardViewModel.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3571,10 +3575,10 @@
A7ED1F931E831C5C00BFFA01 /* LoginViewModelTests.swift */,
D65BF350232FE88300B15B25 /* ManagePledgeSummaryViewModel.swift */,
D65BF352233023E400B15B25 /* ManagePledgeSummaryViewModelTests.swift */,
D67DF563232ABB950051D207 /* ManageViewPledgeViewModel.swift */,
D61440FD23200F09002A6507 /* ManageViewPledgeViewModelTests.swift */,
D67DF563232ABB950051D207 /* ManagePledgeViewModel.swift */,
D61440FD23200F09002A6507 /* ManagePledgeViewModelTests.swift */,
3777F2F62343C7900030BEF5 /* ManageViewPledgeRewardReceivedViewModel.swift */,
3777F2F82343C7AB0030BEF5 /* ManageViewPledgeRewardReceivedViewModelTests.swift */,
D04AAC1B218BB70C00CF713E /* MessageBannerViewModel.swift */,
D04AAC11218BB70A00CF713E /* MessageBannerViewModelTests.swift */,
A7F4419B1D005A9400FE6FC5 /* MessageCellViewModel.swift */,
Expand Down Expand Up @@ -4780,6 +4784,7 @@
A7EDEE571D83453F00780B34 /* PKPaymentAuthorizationViewController+Helpers.swift in Sources */,
D0237C2622BD7B540092C792 /* PledgeSummaryViewModel.swift in Sources */,
01A7A4C01C9690220036E553 /* UITextField+LocalizedPlaceholderKey.swift in Sources */,
3777F2F72343C7900030BEF5 /* ManageViewPledgeRewardReceivedViewModel.swift in Sources */,
0176E13B1C9742FD009CA092 /* UIBarButtonItem.swift in Sources */,
D63BBD35217FAB85007E01F0 /* PaymentMethodsViewModel.swift in Sources */,
8001D4C91D415692009E6667 /* UpdateDraftStyles.swift in Sources */,
Expand Down Expand Up @@ -4866,6 +4871,7 @@
A7ED1FDE1E831C5C00BFFA01 /* DiscoveryExpandableRowCellViewModelTests.swift in Sources */,
D6534D3E22E789B900E9D279 /* PledgePaymentMethodsViewModelTests.swift in Sources */,
A7ED1FC41E831C5C00BFFA01 /* ProjectActivitySuccessCellViewModelTests.swift in Sources */,
3777F2F92343C7AB0030BEF5 /* ManageViewPledgeRewardReceivedViewModelTests.swift in Sources */,
A7ED1FE31E831C5C00BFFA01 /* FindFriendsFaceookConnectCellViewModelTests.swift in Sources */,
D04AACAF218BB72100CF713E /* SettingsViewModelTests.swift in Sources */,
A7ED1FDA1E831C5C00BFFA01 /* DeprecatedRewardPledgeViewModelTests.swift in Sources */,
Expand Down
20 changes: 14 additions & 6 deletions Library/ViewModels/ManagePledgeViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@ public protocol ManagePledgeViewModelInputs {
public protocol ManagePledgeViewModelOutputs {
var configurePaymentMethodView: Signal<GraphUserCreditCard.CreditCard, Never> { get }
var configurePledgeSummaryView: Signal<Project, Never> { get }
var configureRewardReceivedWithProject: Signal<Project, Never> { get }
var configureRewardSummaryView: Signal<Reward, Never> { get }
var goToCancelPledge: Signal<(Project, Backing), Never> { get }
var goToChangePaymentMethod: Signal<Void, Never> { get }
var goToContactCreator: Signal<Void, Never> { get }
var goToRewards: Signal<Project, Never> { get }
var goToUpdatePledge: Signal<(Project, Reward), Never> { get }

var rewardReceivedViewControllerViewIsHidden: Signal<Bool, Never> { get }
var showActionSheetMenuWithOptions: Signal<[ManagePledgeAlertAction], Never> { get }
var title: Signal<String, Never> { get }
}
Expand All @@ -43,6 +44,11 @@ public final class ManagePledgeViewModel:
let projectAndReward = self.projectAndRewardSignal
.takeWhen(self.viewDidLoadSignal.ignoreValues())

let project = projectAndReward.map(first)
let backing = project
.map { $0.personalization.backing }
.skipNil()

self.title = projectAndReward
.map(first)
.map(navigationBarTitle(with:))
Expand All @@ -55,14 +61,11 @@ public final class ManagePledgeViewModel:
self.configurePledgeSummaryView = projectAndReward
.map(first)

self.configureRewardReceivedWithProject = project

self.configureRewardSummaryView = projectAndReward
.map(second)

let project = projectAndReward.map(first)
let backing = project
.map { $0.personalization.backing }
.skipNil()

self.showActionSheetMenuWithOptions = project
.takeWhen(self.menuButtonTappedSignal)
.map { project -> [ManagePledgeAlertAction] in
Expand Down Expand Up @@ -93,6 +96,9 @@ public final class ManagePledgeViewModel:
self.goToChangePaymentMethod = self.menuOptionSelectedSignal
.filter { $0 == .changePaymentMethod }
.ignoreValues()

self.rewardReceivedViewControllerViewIsHidden = projectAndReward
.map { project, reward in reward.isNoReward || project.personalization.backing?.status != .collected }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully this is the same logic @eoji was trying to explain to me ... please let me know if I'm off here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:chefs_kiss: lgtm!

}

private let (projectAndRewardSignal, projectAndRewardObserver) = Signal<(Project, Reward), Never>.pipe()
Expand All @@ -118,12 +124,14 @@ public final class ManagePledgeViewModel:

public let configurePaymentMethodView: Signal<GraphUserCreditCard.CreditCard, Never>
public let configurePledgeSummaryView: Signal<Project, Never>
public let configureRewardReceivedWithProject: Signal<Project, Never>
public let configureRewardSummaryView: Signal<Reward, Never>
public let goToCancelPledge: Signal<(Project, Backing), Never>
public let goToChangePaymentMethod: Signal<Void, Never>
public let goToContactCreator: Signal<Void, Never>
public let goToRewards: Signal<Project, Never>
public let goToUpdatePledge: Signal<(Project, Reward), Never>
public let rewardReceivedViewControllerViewIsHidden: Signal<Bool, Never>
public let showActionSheetMenuWithOptions: Signal<[ManagePledgeAlertAction], Never>
public let title: Signal<String, Never>

Expand Down
Loading