From 2fe9689ef80cdb5cf5e241811c67c26a8fc60d4b Mon Sep 17 00:00:00 2001 From: jlplks Date: Fri, 29 Nov 2024 16:35:34 -0700 Subject: [PATCH 1/3] changed copy on backingfragment whe plot selected --- .../java/com/kickstarter/models/Project.kt | 7 ++ .../viewmodels/BackingFragmentViewModel.kt | 80 +++++++++++++++---- app/src/main/res/values/strings.xml | 2 + 3 files changed, 72 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/com/kickstarter/models/Project.kt b/app/src/main/java/com/kickstarter/models/Project.kt index 2f89300168..23d416ed15 100644 --- a/app/src/main/java/com/kickstarter/models/Project.kt +++ b/app/src/main/java/com/kickstarter/models/Project.kt @@ -34,6 +34,7 @@ class Project private constructor( private val goal: Double, private val id: Long, // in the Kickstarter app, this is project.pid not project.id private val isBacking: Boolean, + private val isPledgeOverTimeAllowed: Boolean?, private val isStarred: Boolean, private val lastUpdatePublishedAt: DateTime?, private val launchedAt: DateTime?, @@ -90,6 +91,7 @@ class Project private constructor( fun goal() = this.goal override fun id() = this.id fun isBacking() = this.isBacking + fun isPledgeOverTimeAllowed() = this.isPledgeOverTimeAllowed fun isStarred() = this.isStarred fun lastUpdatePublishedAt() = this.lastUpdatePublishedAt fun launchedAt() = this.launchedAt @@ -149,6 +151,7 @@ class Project private constructor( private var goal: Double = 0.0, private var id: Long = 0L, private var isBacking: Boolean = false, + private var isPledgeOverTimeAllowed: Boolean? = null, private var isStarred: Boolean = false, private var lastUpdatePublishedAt: DateTime? = null, private var launchedAt: DateTime? = null, @@ -209,6 +212,7 @@ class Project private constructor( fun goal(goal: Double?) = apply { this.goal = goal ?: 0.0 } fun id(id: Long?) = apply { this.id = id ?: 0L } fun isBacking(isBacking: Boolean?) = apply { this.isBacking = isBacking ?: false } + fun isPledgeOverTimeAllowed(isPledgeOverTimeAllowed: Boolean?) = apply { this.isPledgeOverTimeAllowed = isPledgeOverTimeAllowed } fun isStarred(isStarred: Boolean?) = apply { this.isStarred = isStarred ?: false } fun lastUpdatePublishedAt(lastUpdatePublishedAt: DateTime?) = apply { this.lastUpdatePublishedAt = lastUpdatePublishedAt } fun launchedAt(launchedAt: DateTime?) = apply { this.launchedAt = launchedAt } @@ -264,6 +268,7 @@ class Project private constructor( goal = goal, id = id, isBacking = isBacking, + isPledgeOverTimeAllowed = isPledgeOverTimeAllowed, isStarred = isStarred, lastUpdatePublishedAt = lastUpdatePublishedAt, launchedAt = launchedAt, @@ -324,6 +329,7 @@ class Project private constructor( goal = goal, id = id, isBacking = isBacking, + isPledgeOverTimeAllowed = isPledgeOverTimeAllowed, isStarred = isStarred, lastUpdatePublishedAt = lastUpdatePublishedAt, launchedAt = launchedAt, @@ -497,6 +503,7 @@ class Project private constructor( goal() == other.goal() && id() == other.id() && isBacking() == other.isBacking() && + isPledgeOverTimeAllowed() == other.isPledgeOverTimeAllowed() && isStarred() == other.isStarred() && lastUpdatePublishedAt() == other.lastUpdatePublishedAt() && launchedAt() == other.launchedAt() && diff --git a/app/src/main/java/com/kickstarter/viewmodels/BackingFragmentViewModel.kt b/app/src/main/java/com/kickstarter/viewmodels/BackingFragmentViewModel.kt index bed173ba55..40de4afbb2 100644 --- a/app/src/main/java/com/kickstarter/viewmodels/BackingFragmentViewModel.kt +++ b/app/src/main/java/com/kickstarter/viewmodels/BackingFragmentViewModel.kt @@ -7,6 +7,7 @@ import com.kickstarter.R import com.kickstarter.libs.Either import com.kickstarter.libs.Environment import com.kickstarter.libs.KSString +import com.kickstarter.libs.featureflag.FlagKey import com.kickstarter.libs.rx.transformers.Transformers.combineLatestPair import com.kickstarter.libs.rx.transformers.Transformers.neverErrorV2 import com.kickstarter.libs.rx.transformers.Transformers.takePairWhenV2 @@ -240,7 +241,10 @@ interface BackingFragmentViewModel { val reward = Observable.merge(rewardA, rewardB) .distinctUntilChanged() - val isCreator = Observable.combineLatest(this.currentUser.observable(), backedProject) { user, project -> + val isCreator = Observable.combineLatest( + this.currentUser.observable(), + backedProject + ) { user, project -> Pair(user, project) } .map { it.second.userIsCreator(it.first.getValue()) } @@ -295,7 +299,11 @@ interface BackingFragmentViewModel { this.pledgeSummaryIsGone.onNext(it) }.addToDisposable(disposables) - Observable.combineLatest(backedProject, backing, this.currentUser.loggedInUser()) { p, b, user -> Triple(p, b, user) } + Observable.combineLatest( + backedProject, + backing, + this.currentUser.loggedInUser() + ) { p, b, user -> Triple(p, b, user) } .map { pledgeStatusData(it.first, it.second, it.third) } .distinctUntilChanged() .subscribe { this.pledgeStatusData.onNext(it) } @@ -305,7 +313,13 @@ interface BackingFragmentViewModel { .filter { it.shippingAmount().isNotNull() } .map { requireNotNull(it.shippingAmount()) } .compose>(combineLatestPair(backedProject)) - .map { ProjectViewUtils.styleCurrency(it.first.toDouble(), it.second, this.ksCurrency) } + .map { + ProjectViewUtils.styleCurrency( + it.first.toDouble(), + it.second, + this.ksCurrency + ) + } .distinctUntilChanged() .subscribe { this.shippingAmount.onNext(it) } .addToDisposable(disposables) @@ -393,7 +407,10 @@ interface BackingFragmentViewModel { backing .compose>(combineLatestPair(backedProject)) .compose(takePairWhenV2(this.receivedCheckboxToggled)) - .switchMap { this.apiClient.postBacking(it.first.second, it.first.first, it.second).compose(neverErrorV2()) } + .switchMap { + this.apiClient.postBacking(it.first.second, it.first.first, it.second) + .compose(neverErrorV2()) + } .share() .subscribe() @@ -507,7 +524,14 @@ interface BackingFragmentViewModel { return when (CreditCardPaymentType.safeValueOf(paymentSource.paymentType())) { CreditCardPaymentType.ANDROID_PAY -> Either.Right(R.string.googlepay_button_content_description) CreditCardPaymentType.APPLE_PAY -> Either.Right(R.string.apple_pay_content_description) - CreditCardPaymentType.CREDIT_CARD -> Either.Left(StoredCard.issuer(CreditCardTypes.safeValueOf(paymentSource.type()))) + CreditCardPaymentType.CREDIT_CARD -> Either.Left( + StoredCard.issuer( + CreditCardTypes.safeValueOf( + paymentSource.type() + ) + ) + ) + else -> Either.Left(CardBrand.Unknown.code) } } @@ -521,7 +545,11 @@ interface BackingFragmentViewModel { } } - private fun pledgeStatusData(project: Project, backing: Backing, user: User): PledgeStatusData { + private fun pledgeStatusData( + project: Project, + backing: Backing, + user: User + ): PledgeStatusData { var statusStringRes: Int? @@ -534,13 +562,22 @@ interface BackingFragmentViewModel { Backing.STATUS_COLLECTED -> R.string.We_collected_your_pledge_for_this_project Backing.STATUS_DROPPED -> R.string.Your_pledge_was_dropped_because_of_payment_errors Backing.STATUS_ERRORED -> R.string.We_cant_process_your_pledge_Please_update_your_payment_method - Backing.STATUS_PLEDGED -> R.string.If_your_project_reaches_its_funding_goal_the_backer_will_be_charged_total_on_project_deadline + Backing.STATUS_PLEDGED -> { + if (project.isPledgeOverTimeAllowed() == true && + environment.featureFlagClient() + ?.getBoolean(FlagKey.ANDROID_PLEDGE_OVER_TIME) == true + ) { + R.string.fpo_you_have_selected_pledge_over_time_if_the_project_reaches_its_funding_goal_the_first_charge_of + } else { + R.string.If_your_project_reaches_its_funding_goal_the_backer_will_be_charged_total_on_project_deadline + } + } + Backing.STATUS_PREAUTH -> R.string.We_re_processing_your_pledge_pull_to_refresh else -> null } } } else { - statusStringRes = when (project.state()) { Project.STATE_CANCELED -> R.string.You_canceled_this_project_so_the_backers_payment_method_was_never_charged Project.STATE_FAILED -> R.string.Your_project_didnt_reach_its_funding_goal_so_the_backers_payment_method_was_never_charged @@ -603,13 +640,17 @@ interface BackingFragmentViewModel { override fun cardLogo(): Observable = this.cardLogo - override fun fixPaymentMethodButtonIsGone(): Observable = this.fixPaymentMethodButtonIsGone + override fun fixPaymentMethodButtonIsGone(): Observable = + this.fixPaymentMethodButtonIsGone - override fun fixPaymentMethodMessageIsGone(): Observable = this.fixPaymentMethodMessageIsGone + override fun fixPaymentMethodMessageIsGone(): Observable = + this.fixPaymentMethodMessageIsGone - override fun notifyDelegateToRefreshProject(): Observable = this.notifyDelegateToRefreshProject + override fun notifyDelegateToRefreshProject(): Observable = + this.notifyDelegateToRefreshProject - override fun notifyDelegateToShowFixPledge(): Observable = this.notifyDelegateToShowFixPledge + override fun notifyDelegateToShowFixPledge(): Observable = + this.notifyDelegateToShowFixPledge override fun paymentMethodIsGone(): Observable = this.paymentMethodIsGone @@ -621,15 +662,18 @@ interface BackingFragmentViewModel { override fun pledgeSummaryIsGone(): Observable = this.pledgeSummaryIsGone - override fun projectDataAndReward(): Observable> = this.projectDataAndReward + override fun projectDataAndReward(): Observable> = + this.projectDataAndReward - override fun projectDataAndAddOns(): Observable>> = this.addOnsList + override fun projectDataAndAddOns(): Observable>> = + this.addOnsList override fun receivedCheckboxChecked(): Observable = this.receivedCheckboxChecked override fun receivedSectionIsGone(): Observable = this.receivedSectionIsGone - override fun receivedSectionCreatorIsGone(): Observable = this.receivedSectionCreatorIsGone + override fun receivedSectionCreatorIsGone(): Observable = + this.receivedSectionCreatorIsGone override fun shippingAmount(): Observable = this.shippingAmount @@ -639,7 +683,8 @@ interface BackingFragmentViewModel { override fun showUpdatePledgeSuccess(): Observable = this.showUpdatePledgeSuccess - override fun swipeRefresherProgressIsVisible(): Observable = this.swipeRefresherProgressIsVisible + override fun swipeRefresherProgressIsVisible(): Observable = + this.swipeRefresherProgressIsVisible override fun totalAmount(): Observable = this.totalAmount @@ -647,7 +692,8 @@ interface BackingFragmentViewModel { override fun estimatedDelivery(): Observable = this.estimatedDelivery - override fun deliveryDisclaimerSectionIsGone(): Observable = this.deliveryDisclaimerSectionIsGone + override fun deliveryDisclaimerSectionIsGone(): Observable = + this.deliveryDisclaimerSectionIsGone override fun onCleared() { disposables.clear() diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ef69a9738b..9fdade9ae3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -105,4 +105,6 @@ Collected Unattempted Payment schedule + You have selected Pledge Over Time. If the project reaches its funding goal, the first charge of $20 will be collected on March 15, 2024. + From 2d203609dcdb3a6bb5c92a2b91e80d87a19b82d4 Mon Sep 17 00:00:00 2001 From: jlplks Date: Mon, 2 Dec 2024 12:19:48 -0700 Subject: [PATCH 2/3] added test --- .../mock/factories/ProjectFactory.kt | 27 ++++++++++++++- .../BackingFragmentViewModelTest.kt | 34 +++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/kickstarter/mock/factories/ProjectFactory.kt b/app/src/main/java/com/kickstarter/mock/factories/ProjectFactory.kt index 7ed3aca7ce..46a112ae05 100644 --- a/app/src/main/java/com/kickstarter/mock/factories/ProjectFactory.kt +++ b/app/src/main/java/com/kickstarter/mock/factories/ProjectFactory.kt @@ -134,7 +134,32 @@ object ProjectFactory { .isBacking(true) .build() } - + @JvmStatic + fun backedProjectWithPlotSelected(): Project { + val project = project().toBuilder().isPledgeOverTimeAllowed(true).build() + val reward = RewardFactory.reward() + val backing = Backing.builder() + .amount(10.0) + .backerId(IdFactory.id().toLong()) + .cancelable(true) + .id(IdFactory.id().toLong()) + .sequence(1) + .reward(reward) + .rewardId(reward.id()) + .paymentSource(PaymentSourceFactory.visa()) + .pledgedAt(DateTime.now()) + .projectId(project.id()) + .shippingAmount(0.0f) + .status(Backing.STATUS_PLEDGED) + .build() + return project + .toBuilder() + .availableCardTypes(listOf(PaymentSourceFactory.visa().type() ?: CreditCardPaymentType.CREDIT_CARD.rawValue())) + .canComment(true) + .backing(backing) + .isBacking(true) + .build() + } @JvmStatic fun backedProjectWithRewardAndAddOnsLimitReached(): Project { val project = project() diff --git a/app/src/test/java/com/kickstarter/viewmodels/BackingFragmentViewModelTest.kt b/app/src/test/java/com/kickstarter/viewmodels/BackingFragmentViewModelTest.kt index da741b03d9..9295592f41 100644 --- a/app/src/test/java/com/kickstarter/viewmodels/BackingFragmentViewModelTest.kt +++ b/app/src/test/java/com/kickstarter/viewmodels/BackingFragmentViewModelTest.kt @@ -7,9 +7,11 @@ import com.kickstarter.R import com.kickstarter.libs.Either import com.kickstarter.libs.Environment import com.kickstarter.libs.MockCurrentUserV2 +import com.kickstarter.libs.featureflag.FlagKey import com.kickstarter.libs.utils.DateTimeUtils import com.kickstarter.libs.utils.EventName import com.kickstarter.libs.utils.extensions.addToDisposable +import com.kickstarter.mock.MockFeatureFlagClient import com.kickstarter.mock.factories.BackingFactory import com.kickstarter.mock.factories.LocationFactory import com.kickstarter.mock.factories.PaymentSourceFactory @@ -768,6 +770,38 @@ class BackingFragmentViewModelTest : KSRobolectricTestCase() { ) } + @Test + fun testPledgeStatusData_whenPlotIsAllowed() { + val mockFeatureFlagClient = object : MockFeatureFlagClient() { + override fun getBoolean(FlagKey: FlagKey): Boolean { + return true + } + } + val backing = backingWithStatus(Backing.STATUS_PLEDGED) + val deadline = DateTime.parse("2019-11-11T17:10:04+00:00") + val backedProject = ProjectFactory.backedProjectWithPlotSelected() + .toBuilder() + .deadline(deadline) + .build() + + val environment = environment() + .toBuilder() + .featureFlagClient(mockFeatureFlagClient) + .apolloClientV2(mockApolloClientForBacking(backing)) + .currentUserV2(MockCurrentUserV2(UserFactory.user())) + .build() + setUpEnvironment(environment) + this.vm.inputs.configureWith(ProjectDataFactory.project(backedProject)) + + this.pledgeStatusData.assertValue( + PledgeStatusData( + R.string.fpo_you_have_selected_pledge_over_time_if_the_project_reaches_its_funding_goal_the_first_charge_of, + expectedCurrency(environment, backedProject, 20.0), + DateTimeUtils.longDate(deadline) + ) + ) + } + @Test fun testPledgeStatusData_whenBackingIsPreAuth() { val backing = backingWithStatus(Backing.STATUS_PREAUTH) From 202d76f8c7d9937d2b3bdbe7092e7d9650066192 Mon Sep 17 00:00:00 2001 From: Isa Martin Date: Tue, 3 Dec 2024 14:22:21 +0100 Subject: [PATCH 3/3] no message --- .../main/java/com/kickstarter/mock/factories/ProjectFactory.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/kickstarter/mock/factories/ProjectFactory.kt b/app/src/main/java/com/kickstarter/mock/factories/ProjectFactory.kt index 9dd11e638c..688e8fffc3 100644 --- a/app/src/main/java/com/kickstarter/mock/factories/ProjectFactory.kt +++ b/app/src/main/java/com/kickstarter/mock/factories/ProjectFactory.kt @@ -152,7 +152,7 @@ object ProjectFactory { .build() return project .toBuilder() - .availableCardTypes(listOf(PaymentSourceFactory.visa().type() ?: CreditCardPaymentType.CREDIT_CARD.rawValue())) + .availableCardTypes(listOf(PaymentSourceFactory.visa().type() ?: CreditCardPaymentType.CREDIT_CARD.rawValue)) .canComment(true) .backing(backing) .isBacking(true)