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

[💳] Unavailable cards in pledge screen #579

Merged
merged 4 commits into from
Aug 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions app/src/main/java/com/kickstarter/libs/utils/ProjectUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

import com.kickstarter.R;
import com.kickstarter.libs.KSString;
import com.kickstarter.libs.models.Country;
import com.kickstarter.models.Project;
import com.kickstarter.models.StoredCard;
import com.kickstarter.models.User;
import com.kickstarter.services.DiscoveryParams;

Expand All @@ -17,10 +19,19 @@

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import type.CreditCardTypes;

public final class ProjectUtils {
private ProjectUtils() {}

public static boolean acceptedCardType(final @NonNull CreditCardTypes type, final @NonNull Project project) {
if (project.currency().equals(Country.US.getCurrencyCode())) {
return StoredCard.Companion.getUsdCardTypes().contains(type);
} else {
return StoredCard.Companion.getNonUsdCardTypes().contains(type);
}
}

public static List<Pair<Project, DiscoveryParams>> combineProjectsAndParams(final @NonNull List<Project> projects, final @NonNull DiscoveryParams params) {
final ArrayList<Pair<Project, DiscoveryParams>> projectAndParams = new ArrayList<>(projects.size());
for (int i = 0; i < projects.size(); i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ private LocationFactory() {}
.build();
}

public static @NonNull Location mexico() {
return Location.builder()
.id(638242)
.displayableName("Mexico City, Mexico")
.name("Mexico City")
.state("Mexico")
.country("MX")
.build();
}

public static @NonNull Location sydney() {
return Location.builder()
.id(1105779)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ private ProjectFactory() {}
.currentCurrency("MXN")
.currencySymbol("$")
.currency("MXN")
.location(LocationFactory.mexico())
.staticUsdRate(0.75f)
.fxRate(0.75f)
.build();
Expand Down
14 changes: 13 additions & 1 deletion app/src/main/java/com/kickstarter/models/StoredCard.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package com.kickstarter.models
import android.os.Parcelable
import auto.parcel.AutoParcel
import com.kickstarter.R
import com.kickstarter.libs.qualifiers.AutoGson
import type.CreditCardTypes
import java.util.*

Expand Down Expand Up @@ -31,6 +30,19 @@ abstract class StoredCard : Parcelable {
return AutoParcel_StoredCard.Builder()
}

private val allowedCardTypes = listOf(CreditCardTypes.AMEX,
CreditCardTypes.DINERS,
CreditCardTypes.DISCOVER,
CreditCardTypes.JCB,
CreditCardTypes.MASTERCARD,
CreditCardTypes.UNION_PAY,
CreditCardTypes.VISA)

val usdCardTypes = allowedCardTypes;
val nonUsdCardTypes = listOf(CreditCardTypes.AMEX,
CreditCardTypes.MASTERCARD,
CreditCardTypes.VISA)

internal fun getCardTypeDrawable(cardType: CreditCardTypes): Int {
return when (cardType) {
CreditCardTypes.AMEX -> R.drawable.amex_md
Expand Down
15 changes: 10 additions & 5 deletions app/src/main/java/com/kickstarter/ui/adapters/RewardCardAdapter.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.kickstarter.ui.adapters

import android.util.Pair
import android.view.View
import androidx.annotation.NonNull
import androidx.recyclerview.widget.RecyclerView
import com.kickstarter.R
import com.kickstarter.models.Project
import com.kickstarter.models.StoredCard
import com.kickstarter.ui.data.CardState
import com.kickstarter.ui.viewholders.*
import rx.Observable

class RewardCardAdapter(private val delegate: Delegate) : KSAdapter() {
interface Delegate : RewardCardViewHolder.Delegate, RewardPledgeCardViewHolder.Delegate, RewardAddCardViewHolder.Delegate
Expand Down Expand Up @@ -47,9 +49,12 @@ class RewardCardAdapter(private val delegate: Delegate) : KSAdapter() {
}
}

fun takeCards(@NonNull cards: List<StoredCard>) {
fun takeCards(cards: List<StoredCard>, project: Project) {
sections().clear()
addSection(cards)
addSection(Observable.from(cards)
.map { Pair(it, project) }
.toList().toBlocking().single()
)
addSection(listOf(null))
notifyDataSetChanged()
}
Expand All @@ -69,10 +74,10 @@ class RewardCardAdapter(private val delegate: Delegate) : KSAdapter() {
notifyItemChanged(position)
}

fun insertCard(storedCard: StoredCard) : Int {
fun insertCard(storedCardAndProject: Pair<StoredCard, Project>) : Int {
val storedCards = sections()[0]
val position = 0
storedCards.add(position, storedCard)
storedCards.add(position, storedCardAndProject)
notifyItemInserted(position)

return position
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,10 @@ class PledgeFragment : BaseFragment<PledgeFragmentViewModel.ViewModel>(), Reward
.compose(observeForUI())
.subscribe { setTextColor(it, total_amount, total_symbol_start, total_symbol_end) }

this.viewModel.outputs.cards()
this.viewModel.outputs.cardsAndProject()
.compose(bindToLifecycle())
.compose(observeForUI())
.subscribe { (cards_recycler.adapter as RewardCardAdapter).takeCards(it) }
.subscribe { (cards_recycler.adapter as RewardCardAdapter).takeCards(it.first, it.second) }

this.viewModel.outputs.addedCard()
.compose(bindToLifecycle())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package com.kickstarter.ui.viewholders

import android.util.Pair
import android.view.View
import com.kickstarter.R
import com.kickstarter.libs.KSString
import com.kickstarter.libs.rx.transformers.Transformers.observeForUI
import com.kickstarter.libs.utils.ViewUtils
import com.kickstarter.models.Project
import com.kickstarter.models.StoredCard
import com.kickstarter.viewmodels.RewardCardViewHolderViewModel
import kotlinx.android.synthetic.main.item_reward_credit_card.view.*
Expand All @@ -17,15 +20,16 @@ class RewardCardViewHolder(val view : View, val delegate : Delegate) : KSViewHol
private val viewModel: RewardCardViewHolderViewModel.ViewModel = RewardCardViewHolderViewModel.ViewModel(environment())
private val ksString: KSString = environment().ksString()

private val cardNotAllowedString = this.context().getString(R.string.You_cant_use_this_credit_card_to_back_a_project_from_project_country)
private val creditCardExpirationString = this.context().getString(R.string.Credit_card_expiration)
private val cardEndingInString = this.context().getString(R.string.Card_ending_in_last_four)
private val endingInString = this.context().getString(R.string.Ending_in_last_four)

init {

this.viewModel.outputs.expirationDate()
.compose(bindToLifecycle())
.compose(observeForUI())
.subscribe { setExpirationDateTextView(it) }
.subscribe { setExpirationDateText(it) }

this.viewModel.outputs.issuerImage()
.compose(bindToLifecycle())
Expand All @@ -35,25 +39,51 @@ class RewardCardViewHolder(val view : View, val delegate : Delegate) : KSViewHol
this.viewModel.outputs.lastFour()
.compose(bindToLifecycle())
.compose(observeForUI())
.subscribe { setLastFourTextView(it) }
.subscribe { setLastFourText(it) }

this.viewModel.outputs.buttonCTA()
.compose(bindToLifecycle())
.compose(observeForUI())
.subscribe { this.view.select_button.setText(it) }

this.viewModel.outputs.buttonEnabled()
.compose(bindToLifecycle())
.compose(observeForUI())
.subscribe { this.view.select_button.isEnabled = it }

this.viewModel.outputs.notAvailableCopyIsVisible()
.compose(bindToLifecycle())
.compose(observeForUI())
.subscribe { ViewUtils.setGone(this.view.card_not_allowed_warning, !it) }

this.viewModel.outputs.projectCountry()
.compose(bindToLifecycle())
.compose(observeForUI())
.subscribe { setCardNotAllowedWarningText(it) }

this.view.select_button.setOnClickListener {
this.delegate.selectCardButtonClicked(adapterPosition)
}
}

override fun bindData(data: Any?) {
val card = requireNotNull(data as StoredCard)
this.viewModel.inputs.configureWith(card)
@Suppress("UNCHECKED_CAST")
val cardAndProject = requireNotNull(data) as Pair<StoredCard, Project>
this.viewModel.inputs.configureWith(cardAndProject)
}

private fun setCardNotAllowedWarningText(country: String) {
this.view.card_not_allowed_warning.text = this.ksString.format(this.cardNotAllowedString,
"project_country", country)
}

private fun setExpirationDateTextView(date: String) {
private fun setExpirationDateText(date: String) {
this.view.reward_card_expiration_date.text = this.ksString.format(this.creditCardExpirationString,
"expiration_date", date)
}

private fun setLastFourTextView(lastFour: String) {
this.view.reward_card_last_four.text = this.ksString.format(this.cardEndingInString, "last_four", lastFour)
private fun setLastFourText(lastFour: String) {
this.view.reward_card_last_four.text = this.ksString.format(this.endingInString, "last_four", lastFour)
}

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.kickstarter.ui.viewholders

import android.util.Pair
import android.view.View
import com.kickstarter.R
import com.kickstarter.libs.KSString
import com.kickstarter.libs.rx.transformers.Transformers.observeForUI
import com.kickstarter.libs.utils.AnimationUtils
import com.kickstarter.models.Project
import com.kickstarter.models.StoredCard
import com.kickstarter.viewmodels.RewardLoadingCardViewHolderViewModel
import kotlinx.android.synthetic.main.item_reward_loading_card.view.*
Expand All @@ -15,7 +17,7 @@ class RewardLoadingCardViewHolder(val view: View) : KSViewHolder(view) {
private val ksString: KSString = environment().ksString()

private val creditCardExpirationString = this.context().getString(R.string.Credit_card_expiration)
private val cardEndingInString = this.context().getString(R.string.Card_ending_in_last_four)
private val endingInString = this.context().getString(R.string.Ending_in_last_four)

init {

Expand Down Expand Up @@ -45,8 +47,9 @@ class RewardLoadingCardViewHolder(val view: View) : KSViewHolder(view) {
}

override fun bindData(data: Any?) {
val card = requireNotNull(data as StoredCard)
this.viewModel.inputs.configureWith(card)
@Suppress("UNCHECKED_CAST")
val cardAndProject = requireNotNull(data) as Pair<StoredCard, Project>
this.viewModel.inputs.configureWith(cardAndProject)
}

private fun setExpirationDateTextView(date: String) {
Expand All @@ -55,7 +58,7 @@ class RewardLoadingCardViewHolder(val view: View) : KSViewHolder(view) {
}

private fun setLastFourTextView(lastFour: String) {
this.view.reward_loading_card_last_four.text = this.ksString.format(this.cardEndingInString, "last_four", lastFour)
this.view.reward_loading_card_last_four.text = this.ksString.format(this.endingInString, "last_four", lastFour)
}

}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.kickstarter.ui.viewholders

import android.util.Pair
import android.view.View
import com.kickstarter.R
import com.kickstarter.libs.KSString
import com.kickstarter.libs.rx.transformers.Transformers.observeForUI
import com.kickstarter.models.Project
import com.kickstarter.models.StoredCard
import com.kickstarter.viewmodels.RewardPledgeCardViewHolderViewModel
import kotlinx.android.synthetic.main.item_reward_pledge_card.view.*
Expand All @@ -16,7 +18,7 @@ class RewardPledgeCardViewHolder(val view : View, val delegate : Delegate) : KSV
}

private val creditCardExpirationString = this.context().getString(R.string.Credit_card_expiration)
private val cardEndingInString = this.context().getString(R.string.Card_ending_in_last_four)
private val endingInString = this.context().getString(R.string.Ending_in_last_four)

private val viewModel: RewardPledgeCardViewHolderViewModel.ViewModel = RewardPledgeCardViewHolderViewModel.ViewModel(environment())
private val ksString: KSString = environment().ksString()
Expand Down Expand Up @@ -53,8 +55,9 @@ class RewardPledgeCardViewHolder(val view : View, val delegate : Delegate) : KSV
}

override fun bindData(data: Any?) {
val card = requireNotNull(data as StoredCard)
this.viewModel.inputs.configureWith(card)
@Suppress("UNCHECKED_CAST")
val cardAndProject = requireNotNull(data) as Pair<StoredCard, Project>
this.viewModel.inputs.configureWith(cardAndProject)
}

private fun setExpirationDateTextView(date: String) {
Expand All @@ -63,7 +66,7 @@ class RewardPledgeCardViewHolder(val view : View, val delegate : Delegate) : KSV
}

private fun setLastFourTextView(lastFour: String) {
this.view.reward_pledge_card_last_four.text = this.ksString.format(this.cardEndingInString, "last_four", lastFour)
this.view.reward_pledge_card_last_four.text = this.ksString.format(this.endingInString, "last_four", lastFour)
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.kickstarter.viewmodels

import android.util.Pair
import com.kickstarter.libs.ActivityViewModel
import com.kickstarter.libs.Environment
import com.kickstarter.models.Project
import com.kickstarter.models.StoredCard
import com.kickstarter.ui.viewholders.KSViewHolder
import rx.Observable
Expand All @@ -12,8 +14,8 @@ import java.util.*

interface BaseRewardCardViewHolderViewModel {
interface Inputs {
/** Call to configure view model with a stored card. */
fun configureWith(storedCard: StoredCard)
/** Call to configure view model with a stored card and project. */
fun configureWith(cardAndProject: Pair<StoredCard, Project>)
}

interface Outputs {
Expand All @@ -31,7 +33,7 @@ interface BaseRewardCardViewHolderViewModel {
}

abstract class ViewModel(val environment: Environment) : ActivityViewModel<KSViewHolder>(environment), Inputs, Outputs {
private val card = PublishSubject.create<StoredCard>()
protected val cardAndProject: PublishSubject<Pair<StoredCard, Project>> = PublishSubject.create()

private val expirationDate = BehaviorSubject.create<String>()
private val id = BehaviorSubject.create<String>()
Expand All @@ -41,22 +43,26 @@ interface BaseRewardCardViewHolderViewModel {
private val sdf = SimpleDateFormat(StoredCard.DATE_FORMAT, Locale.getDefault())

init {
this.card.map { it.id() }

val card = cardAndProject
.map { it.first }

card.map { it.id() }
.subscribe(this.id)

this.card.map { it.expiration() }
card.map { it.expiration() }
.map { sdf.format(it).toString() }
.subscribe { this.expirationDate.onNext(it) }

this.card.map { it.lastFourDigits() }
card.map { it.lastFourDigits() }
.subscribe { this.lastFour.onNext(it) }

this.card.map { it.type() }
card.map { it.type() }
.map { StoredCard.getCardTypeDrawable(it) }
.subscribe { this.issuerImage.onNext(it) }

}
override fun configureWith(storedCard: StoredCard) = this.card.onNext(storedCard)
override fun configureWith(cardAndProject: Pair<StoredCard, Project>) = this.cardAndProject.onNext(cardAndProject)

override fun id(): Observable<String> = this.id

Expand Down