-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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-280] Manage pledge screen from CTA container #831
Changes from all commits
d5b28d8
257fe50
98f515d
d12f942
622d1e5
0429d3e
d2e841e
3f40c69
1ac60bf
cce443e
d0d9067
101bc7a
f839d70
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -135,6 +135,26 @@ public final class ProjectPamphletViewController: UIViewController { | |
self?.goToRewards(project: project, refTag: refTag) | ||
} | ||
|
||
self.viewModel.outputs.goToManageViewPledge | ||
.observeForControllerAction() | ||
.observeValues { [weak self] params in | ||
let (project, reward, refTag) = params | ||
|
||
self?.goToManageViewPledge(project: project, reward: reward, refTag: refTag) | ||
} | ||
|
||
self.viewModel.outputs.goToDeprecatedViewBacking | ||
.observeForControllerAction() | ||
.observeValues { [weak self] project, user in | ||
self?.goToDeprecatedViewBacking(project: project, user: user) | ||
} | ||
|
||
self.viewModel.outputs.goToDeprecatedManagePledge | ||
.observeForControllerAction() | ||
.observeValues { [weak self] project, reward, refTag in | ||
self?.goToDeprecatedManagePledge(project: project, reward: reward, refTag: refTag) | ||
} | ||
|
||
self.viewModel.outputs.configureChildViewControllersWithProject | ||
.observeForUI() | ||
.observeValues { [weak self] project, refTag in | ||
|
@@ -186,6 +206,44 @@ public final class ProjectPamphletViewController: UIViewController { | |
self.present(vc, animated: true) | ||
} | ||
|
||
private func goToManageViewPledge(project: Project, reward: Reward, refTag _: RefTag?) { | ||
let managePledgeViewController = ManagePledgeViewController.instantiate() | ||
managePledgeViewController.configureWith(project: project, reward: reward) | ||
|
||
let nav = UINavigationController(rootViewController: managePledgeViewController) | ||
if AppEnvironment.current.device.userInterfaceIdiom == .pad { | ||
_ = nav | ||
|> \.modalPresentationStyle .~ .formSheet | ||
} | ||
self.present(nav, animated: true) | ||
} | ||
|
||
private func goToDeprecatedManagePledge(project: Project, reward: Reward, refTag _: RefTag?) { | ||
let pledgeViewController = DeprecatedRewardPledgeViewController | ||
.configuredWith( | ||
project: project, reward: reward | ||
) | ||
|
||
let nav = UINavigationController(rootViewController: pledgeViewController) | ||
if AppEnvironment.current.device.userInterfaceIdiom == .pad { | ||
_ = nav | ||
|> \.modalPresentationStyle .~ .formSheet | ||
} | ||
self.present(nav, animated: true) | ||
} | ||
|
||
private func goToDeprecatedViewBacking(project: Project, user _: User?) { | ||
let backingViewController = BackingViewController.configuredWith(project: project, backer: nil) | ||
|
||
if AppEnvironment.current.device.userInterfaceIdiom == .pad { | ||
let nav = UINavigationController(rootViewController: backingViewController) | ||
|> \.modalPresentationStyle .~ .formSheet | ||
self.present(nav, animated: true) | ||
} else { | ||
self.navigationController?.pushViewController(backingViewController, animated: true) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, I know we've previously discussed the fact that we're presenting manage screen over the previous context using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The from |
||
} | ||
} | ||
|
||
private func updateContentInsets() { | ||
let buttonSize = self.pledgeCTAContainerView.pledgeCTAButton.systemLayoutSizeFitting( | ||
UIView.layoutFittingCompressedSize | ||
|
@@ -203,8 +261,8 @@ public final class ProjectPamphletViewController: UIViewController { | |
} | ||
|
||
extension ProjectPamphletViewController: PledgeCTAContainerViewDelegate { | ||
func pledgeCTAButtonTapped() { | ||
self.viewModel.inputs.backThisProjectTapped() | ||
func pledgeCTAButtonTapped(with state: PledgeStateCTAType) { | ||
self.viewModel.inputs.pledgeCTAButtonTapped(with: state) | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,10 @@ | ||
import KsApi | ||
import Prelude | ||
import ReactiveSwift | ||
public protocol ProjectPamphletViewModelInputs { | ||
/// Call when "Back this project" is tapped | ||
func backThisProjectTapped() | ||
|
||
public typealias BackingData = (Project, User?) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like // BackingViewModel.swift
fileprivate let projectAndBackerProperty = MutableProperty<(Project, User?)?>(nil) could use this data type...should we update it? // BackingViewModel.swift
fileprivate let projectAndBackerProperty = MutableProperty<BackingData?>(nil) |
||
|
||
public protocol ProjectPamphletViewModelInputs { | ||
/// Call with the project given to the view controller. | ||
func configureWith(projectOrParam: Either<Project, Param>, refTag: RefTag?) | ||
|
||
|
@@ -14,6 +14,9 @@ public protocol ProjectPamphletViewModelInputs { | |
/// Call after the view loads and passes the initial TopConstraint constant. | ||
func initial(topConstraint: CGFloat) | ||
|
||
/// Call when the pledge CTA button is tapped | ||
func pledgeCTAButtonTapped(with state: PledgeStateCTAType) | ||
|
||
/// Call when pledgeRetryButton is tapped. | ||
func pledgeRetryButtonTapped() | ||
|
||
|
@@ -34,6 +37,12 @@ public protocol ProjectPamphletViewModelOutputs { | |
/// Emits a (project, isLoading) tuple used to configure the pledge CTA view | ||
var configurePledgeCTAView: Signal<(Either<Project, ErrorEnvelope>, Bool), Never> { get } | ||
|
||
var goToDeprecatedManagePledge: Signal<PledgeData, Never> { get } | ||
|
||
var goToDeprecatedViewBacking: Signal<BackingData, Never> { get } | ||
|
||
var goToManageViewPledge: Signal<PledgeData, Never> { get } | ||
|
||
/// Emits a project and refTag to be used to navigate to the reward selection screen. | ||
var goToRewards: Signal<(Project, RefTag?), Never> { get } | ||
|
||
|
@@ -80,13 +89,38 @@ public final class ProjectPamphletViewModel: ProjectPamphletViewModelType, Proje | |
let freshProjectAndRefTag = freshProjectAndRefTagEvent.values() | ||
|
||
let ctaButtonTapped = freshProjectAndRefTag | ||
.takeWhen(self.backThisProjectTappedProperty.signal) | ||
.map { project, refTag in | ||
(project, refTag) | ||
.takePairWhen(self.pledgeCTAButtonTappedProperty.signal) | ||
.map(unpack) | ||
|
||
let goToManagePledge = ctaButtonTapped | ||
.filter { canShowManageViewPledgeScreen($0.0, state:$0.2) } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looking at this in action, it might actually be more readable to name those params. I'll leave this out to you, I'm OK with both - but wanted to raise it in case you were in favour of the other option.
(this of course would apply to other places in this PR. |
||
.map { (project, refTag, _) -> PledgeData in | ||
PledgeData(project: project, | ||
reward: reward(from: project.personalization.backing, inProject: project), | ||
refTag: refTag) | ||
} | ||
|
||
self.goToManageViewPledge = goToManagePledge | ||
.filter { _ in featureNativeCheckoutPledgeViewIsEnabled() } | ||
|
||
self.goToDeprecatedManagePledge = ctaButtonTapped | ||
.filter { shouldGoToDeprecatedManagePledge($0.0, state:$0.2) } | ||
.map { (project, refTag, _) -> PledgeData in | ||
PledgeData(project: project, | ||
reward: reward(from: project.personalization.backing, inProject: project), | ||
refTag: refTag) | ||
} | ||
|
||
self.goToDeprecatedViewBacking = ctaButtonTapped | ||
.map { project, _, state in (project, state) } | ||
.filter { shouldGoToDeprecatedViewBacking($0.0, state:$0.1) } | ||
.map { project, _ in | ||
BackingData(project, AppEnvironment.current.currentUser) | ||
} | ||
|
||
self.goToRewards = ctaButtonTapped | ||
.filter { _ in userCanSeeNativeCheckout() } | ||
.filter { canShowRewardsScreen($0.0, state:$0.2) } | ||
.map { project, refTag, _ in (project, refTag) } | ||
|
||
let project = freshProjectAndRefTag | ||
.map(first) | ||
|
@@ -148,9 +182,9 @@ public final class ProjectPamphletViewModel: ProjectPamphletViewModelType, Proje | |
.observeValues { AppEnvironment.current.cookieStorage.setCookie($0) } | ||
} | ||
|
||
private let backThisProjectTappedProperty = MutableProperty(()) | ||
public func backThisProjectTapped() { | ||
self.backThisProjectTappedProperty.value = () | ||
private let pledgeCTAButtonTappedProperty = MutableProperty<PledgeStateCTAType?>(nil) | ||
public func pledgeCTAButtonTapped(with state: PledgeStateCTAType) { | ||
self.pledgeCTAButtonTappedProperty.value = state | ||
} | ||
|
||
private let configDataProperty = MutableProperty<(Either<Project, Param>, RefTag?)?>(nil) | ||
|
@@ -191,6 +225,9 @@ public final class ProjectPamphletViewModel: ProjectPamphletViewModelType, Proje | |
|
||
public let configureChildViewControllersWithProject: Signal<(Project, RefTag?), Never> | ||
public let configurePledgeCTAView: Signal<(Either<Project, ErrorEnvelope>, Bool), Never> | ||
public let goToDeprecatedManagePledge: Signal<PledgeData, Never> | ||
public let goToDeprecatedViewBacking: Signal<BackingData, Never> | ||
public let goToManageViewPledge: Signal<PledgeData, Never> | ||
public let goToRewards: Signal<(Project, RefTag?), Never> | ||
public let setNavigationBarHiddenAnimated: Signal<(Bool, Bool), Never> | ||
public let setNeedsStatusBarAppearanceUpdate: Signal<(), Never> | ||
|
@@ -284,3 +321,37 @@ private func fetchProject(projectOrParam: Either<Project, Param>, shouldPrefix: | |
|
||
return projectProducer | ||
} | ||
|
||
private func reward(from backing: Backing?, inProject project: Project) -> Reward { | ||
return backing?.reward | ||
?? project.rewards.filter { $0.id == backing?.rewardId }.first | ||
?? Reward.noReward | ||
} | ||
|
||
private func canShowRewardsScreen(_: Project, state: PledgeStateCTAType?) -> Bool { | ||
guard let state = state else { | ||
return false | ||
} | ||
return userCanSeeNativeCheckout() && (state == .pledge || state == .viewRewards) | ||
} | ||
|
||
private func canShowManageViewPledgeScreen(_ project: Project, state: PledgeStateCTAType?) -> Bool { | ||
guard let isBacking = project.personalization.isBacking, let state = state else { | ||
return false | ||
} | ||
return isBacking && (state == .manage || state == .viewBacking) | ||
} | ||
|
||
private func shouldGoToDeprecatedViewBacking(_ project: Project, state: PledgeStateCTAType?) -> Bool { | ||
guard let isBacking = project.personalization.isBacking, let state = state else { | ||
return false | ||
} | ||
return !featureNativeCheckoutPledgeViewIsEnabled() && isBacking && state == .viewBacking | ||
} | ||
|
||
private func shouldGoToDeprecatedManagePledge(_ project: Project, state: PledgeStateCTAType?) -> Bool { | ||
guard let isBacking = project.personalization.isBacking, let state = state else { | ||
return false | ||
} | ||
return !featureNativeCheckoutPledgeViewIsEnabled() && isBacking && state == .manage | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm seeing a lot of inconsistencies between the naming of VMs
output
signal and theprivate
action on the controller...do you think it would be worth it cleaning this up..So for example:
self.viewModel.outputs.goToManageViewPledge
would triggerself?.goToManageViewPledge
, etc...For the
deprecated
ones I'd suggest we simply add it as a suffix:self.viewModel.outputs.goToViewBackingDeprecated
links toself?.goToViewBacking
...There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It makes sense to change the
private
actions to match the name of the output. Will change that.Regarding the
deprecated
naming, I'm following the naming convention that we adopted for deprecated classes (DeprecatedCheckoutViewModel
,DeprecatedRewardPledgeViewController
,DeprecatedRewardCell
etc)