diff --git a/Kickstarter-iOS/Views/Controllers/RewardsCollectionViewController.swift b/Kickstarter-iOS/Views/Controllers/RewardsCollectionViewController.swift index 231d2505c6..5e952c47ec 100644 --- a/Kickstarter-iOS/Views/Controllers/RewardsCollectionViewController.swift +++ b/Kickstarter-iOS/Views/Controllers/RewardsCollectionViewController.swift @@ -13,7 +13,7 @@ final class RewardsCollectionViewController: UICollectionViewController { // MARK: - Properties private let dataSource = RewardsCollectionViewDataSource() - private let viewModel = RewardsCollectionViewModel() + fileprivate let viewModel = RewardsCollectionViewModel() private let hiddenPagingScrollView: UIScrollView = { UIScrollView() @@ -111,6 +111,12 @@ final class RewardsCollectionViewController: UICollectionViewController { self?.dataSource.load(rewards: rewards) self?.collectionView.reloadData() } + + self.viewModel.outputs.goToPledge + .observeForControllerAction() + .observeValues { [weak self] project, reward, refTag in + self?.goToPledge(project: project, reward: reward, refTag: refTag) + } } // MARK: - Private Helpers @@ -190,6 +196,13 @@ final class RewardsCollectionViewController: UICollectionViewController { return CGSize(width: itemWidth, height: itemHeight) } + private func goToPledge(project: Project, reward: Reward, refTag: RefTag?) { + let pledgeViewController = PledgeViewController.instantiate() + pledgeViewController.configureWith(project: project, reward: reward) + + self.navigationController?.pushViewController(pledgeViewController, animated: true) + } + // MARK: - Public Functions @objc func closeButtonTapped() { @@ -197,6 +210,14 @@ final class RewardsCollectionViewController: UICollectionViewController { } } +// MARK: - UICollectionViewDelegate + +extension RewardsCollectionViewController { + override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + self.viewModel.inputs.rewardSelected(at: indexPath.row) + } +} + // MARK: - UIScrollViewDelegate extension RewardsCollectionViewController { diff --git a/Library/ViewModels/RewardsCollectionViewModel.swift b/Library/ViewModels/RewardsCollectionViewModel.swift index 3e0d5366d9..46f5e7bdda 100644 --- a/Library/ViewModels/RewardsCollectionViewModel.swift +++ b/Library/ViewModels/RewardsCollectionViewModel.swift @@ -4,12 +4,16 @@ import Result import KsApi import Prelude +public typealias PledgeData = (project: Project, reward: Reward, refTag: RefTag?) + public protocol RewardsCollectionViewModelOutputs { + var goToPledge: Signal { get } var reloadDataWithRewards: Signal<[Reward], NoError> { get } } public protocol RewardsCollectionViewModelInputs { func configure(with project: Project, refTag: RefTag?) + func rewardSelected(at index: Int) func viewDidLoad() } @@ -27,6 +31,17 @@ RewardsCollectionViewModelInputs, RewardsCollectionViewModelOutputs { ) .map(first) .map { $0.rewards } + + let selectedReward = reloadDataWithRewards + .takePairWhen(self.rewardSelectedIndexProperty.signal.skipNil()) + .map { rewards, index in rewards[index] } + + self.goToPledge = Signal.combineLatest(self.configureWithProjectProperty.signal.skipNil(), + selectedReward, + self.configureWithRefTagProperty.signal) + .map { project, reward, refTag in + return PledgeData(project: project, reward: reward, refTag: refTag) + } } private let configureWithProjectProperty = MutableProperty(nil) @@ -36,11 +51,17 @@ RewardsCollectionViewModelInputs, RewardsCollectionViewModelOutputs { self.configureWithRefTagProperty.value = refTag } + private let rewardSelectedIndexProperty = MutableProperty(nil) + public func rewardSelected(at index: Int) { + self.rewardSelectedIndexProperty.value = index + } + private let viewDidLoadProperty = MutableProperty(()) public func viewDidLoad() { self.viewDidLoadProperty.value = () } + public let goToPledge: Signal public let reloadDataWithRewards: Signal<[Reward], NoError> public var inputs: RewardsCollectionViewModelInputs { return self } diff --git a/Library/ViewModels/RewardsCollectionViewModelTests.swift b/Library/ViewModels/RewardsCollectionViewModelTests.swift index 697ff784bd..cbe82dc06b 100644 --- a/Library/ViewModels/RewardsCollectionViewModelTests.swift +++ b/Library/ViewModels/RewardsCollectionViewModelTests.swift @@ -9,11 +9,17 @@ import ReactiveExtensions_TestHelpers final class RewardsCollectionViewModelTests: TestCase { private let vm: RewardsCollectionViewModelType = RewardsCollectionViewModel() + private let goToPledgeProject = TestObserver() + private let goToPledgeRefTag = TestObserver() + private let goToPledgeReward = TestObserver() private let reloadDataWithRewards = TestObserver<[Reward], NoError>() override func setUp() { super.setUp() + self.vm.outputs.goToPledge.map { $0.project }.observe(self.goToPledgeProject.observer) + self.vm.outputs.goToPledge.map { $0.reward }.observe(self.goToPledgeReward.observer) + self.vm.outputs.goToPledge.map { $0.refTag }.observe(self.goToPledgeRefTag.observer) self.vm.outputs.reloadDataWithRewards.observe(self.reloadDataWithRewards.observer) } @@ -33,4 +39,29 @@ final class RewardsCollectionViewModelTests: TestCase { XCTAssertTrue(value?.count == rewardsCount) } + + func testGoToPledge() { + let project = Project.cosmicSurgery + + self.vm.inputs.configure(with: project, refTag: .activity) + self.vm.inputs.viewDidLoad() + + self.goToPledgeProject.assertDidNotEmitValue() + self.goToPledgeReward.assertDidNotEmitValue() + self.goToPledgeRefTag.assertDidNotEmitValue() + + self.vm.inputs.rewardSelected(at: 0) + + self.goToPledgeProject.assertValues([project]) + self.goToPledgeReward.assertValues([project.rewards[0]]) + self.goToPledgeRefTag.assertValues([.activity]) + + let endIndex = project.rewards.endIndex + + self.vm.inputs.rewardSelected(at: endIndex - 1) + + self.goToPledgeProject.assertValues([project, project]) + self.goToPledgeReward.assertValues([project.rewards[0], project.rewards[endIndex - 1]]) + self.goToPledgeRefTag.assertValues([.activity, .activity]) + } }