mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-22 02:36:55 +00:00
Add minimum amount error for boosts.
This commit is contained in:
committed by
Cody Henthorne
parent
1618141342
commit
0bef37bfc1
@@ -85,6 +85,16 @@ fun DonationsConfiguration.getSubscriptionLevels(): Map<Int, LevelConfiguration>
|
||||
return levels.filterKeys { SUBSCRIPTION_LEVELS.contains(it) }.toSortedMap()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a map describing the minimum donation amounts per currency.
|
||||
* This returns only the currencies available to the user.
|
||||
*/
|
||||
fun DonationsConfiguration.getMinimumDonationAmounts(paymentMethodAvailability: PaymentMethodAvailability = DefaultPaymentMethodAvailability): Map<Currency, FiatMoney> {
|
||||
return getFilteredCurrencies(paymentMethodAvailability)
|
||||
.mapKeys { Currency.getInstance(it.key.uppercase()) }
|
||||
.mapValues { FiatMoney(it.value.minimum, it.key) }
|
||||
}
|
||||
|
||||
private fun DonationsConfiguration.getFilteredCurrencies(paymentMethodAvailability: PaymentMethodAvailability): Map<String, DonationsConfiguration.CurrencyConfiguration> {
|
||||
val userPaymentMethods = paymentMethodAvailability.toSet()
|
||||
val availableCurrencyCodes = PlatformCurrencyUtil.getAvailableCurrencyCodes()
|
||||
|
||||
@@ -64,6 +64,13 @@ class OneTimeDonationRepository(private val donationsService: DonationsService)
|
||||
.map { it.getBoostBadges().first() }
|
||||
}
|
||||
|
||||
fun getMinimumDonationAmounts(): Single<Map<Currency, FiatMoney>> {
|
||||
return Single.fromCallable { donationsService.getDonationsConfiguration(Locale.getDefault()) }
|
||||
.flatMap { it.flattenResult() }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.map { it.getMinimumDonationAmounts() }
|
||||
}
|
||||
|
||||
fun waitForOneTimeRedemption(
|
||||
price: FiatMoney,
|
||||
paymentIntentId: String,
|
||||
|
||||
@@ -10,6 +10,7 @@ import android.text.Spanned
|
||||
import android.text.TextWatcher
|
||||
import android.text.method.DigitsKeyListener
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.appcompat.widget.AppCompatEditText
|
||||
import androidx.core.animation.doOnEnd
|
||||
@@ -26,6 +27,7 @@ import org.thoughtcrime.securesms.util.ViewUtil
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.MappingViewHolder
|
||||
import org.thoughtcrime.securesms.util.visible
|
||||
import java.lang.Integer.min
|
||||
import java.text.DecimalFormatSymbols
|
||||
import java.text.NumberFormat
|
||||
@@ -102,7 +104,9 @@ data class Boost(
|
||||
val currency: Currency,
|
||||
override val isEnabled: Boolean,
|
||||
val onBoostClick: (View, Boost) -> Unit,
|
||||
val minimumAmount: FiatMoney,
|
||||
val isCustomAmountFocused: Boolean,
|
||||
val isCustomAmountTooSmall: Boolean,
|
||||
val onCustomAmountChanged: (String) -> Unit,
|
||||
val onCustomAmountFocusChanged: (Boolean) -> Unit,
|
||||
) : PreferenceModel<SelectionModel>(isEnabled = isEnabled) {
|
||||
@@ -113,7 +117,10 @@ data class Boost(
|
||||
newItem.boosts == boosts &&
|
||||
newItem.selectedBoost == selectedBoost &&
|
||||
newItem.currency == currency &&
|
||||
newItem.isCustomAmountFocused == isCustomAmountFocused
|
||||
newItem.isCustomAmountFocused == isCustomAmountFocused &&
|
||||
newItem.isCustomAmountTooSmall == isCustomAmountTooSmall &&
|
||||
newItem.minimumAmount.amount == minimumAmount.amount &&
|
||||
newItem.minimumAmount.currency == minimumAmount.currency
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +133,7 @@ data class Boost(
|
||||
private val boost5: MaterialButton = itemView.findViewById(R.id.boost_5)
|
||||
private val boost6: MaterialButton = itemView.findViewById(R.id.boost_6)
|
||||
private val custom: AppCompatEditText = itemView.findViewById(R.id.boost_custom)
|
||||
private val error: TextView = itemView.findViewById(R.id.boost_custom_too_small)
|
||||
|
||||
private val boostButtons: List<MaterialButton>
|
||||
get() {
|
||||
@@ -145,6 +153,16 @@ data class Boost(
|
||||
override fun bind(model: SelectionModel) {
|
||||
itemView.isEnabled = model.isEnabled
|
||||
|
||||
error.text = context.getString(
|
||||
R.string.Boost__the_minimum_amount_you_can_donate_is_s,
|
||||
FiatMoneyUtil.format(
|
||||
context.resources, model.minimumAmount,
|
||||
FiatMoneyUtil.formatOptions().trimZerosAfterDecimal()
|
||||
)
|
||||
)
|
||||
|
||||
error.visible = model.isCustomAmountTooSmall
|
||||
|
||||
model.boosts.zip(boostButtons).forEach { (boost, button) ->
|
||||
val isSelected = boost == model.selectedBoost && !model.isCustomAmountFocused
|
||||
button.isSelected = isSelected
|
||||
|
||||
@@ -242,6 +242,7 @@ class DonateToSignalFragment :
|
||||
when (state.donateToSignalType) {
|
||||
DonateToSignalType.ONE_TIME -> displayOneTimeSelection(state.areFieldsEnabled, state.oneTimeDonationState)
|
||||
DonateToSignalType.MONTHLY -> displayMonthlySelection(state.areFieldsEnabled, state.monthlyDonationState)
|
||||
DonateToSignalType.GIFT -> error("This fragment does not support gifts.")
|
||||
}
|
||||
|
||||
space(20.dp)
|
||||
@@ -310,6 +311,8 @@ class DonateToSignalFragment :
|
||||
selectedBoost = state.selectedBoost,
|
||||
currency = state.customAmount.currency,
|
||||
isCustomAmountFocused = state.isCustomAmountFocused,
|
||||
isCustomAmountTooSmall = state.shouldDisplayCustomAmountTooSmallError,
|
||||
minimumAmount = state.minimumDonationAmountOfSelectedCurrency,
|
||||
isEnabled = areFieldsEnabled,
|
||||
onBoostClick = { view, boost ->
|
||||
startAnimationAboveSelectedBoost(view)
|
||||
|
||||
@@ -81,9 +81,15 @@ data class DonateToSignalState(
|
||||
val customAmount: FiatMoney = FiatMoney(BigDecimal.ZERO, selectedCurrency),
|
||||
val isCustomAmountFocused: Boolean = false,
|
||||
val donationStage: DonationStage = DonationStage.INIT,
|
||||
val selectableCurrencyCodes: List<String> = emptyList()
|
||||
val selectableCurrencyCodes: List<String> = emptyList(),
|
||||
private val minimumDonationAmounts: Map<Currency, FiatMoney> = emptyMap()
|
||||
) {
|
||||
val isSelectionValid: Boolean = if (isCustomAmountFocused) customAmount.amount > BigDecimal.ZERO else selectedBoost != null
|
||||
val minimumDonationAmountOfSelectedCurrency: FiatMoney = minimumDonationAmounts[selectedCurrency] ?: FiatMoney(BigDecimal.ZERO, selectedCurrency)
|
||||
private val isCustomAmountTooSmall: Boolean = if (isCustomAmountFocused) customAmount.amount < minimumDonationAmountOfSelectedCurrency.amount else false
|
||||
private val isCustomAmountZero: Boolean = customAmount.amount == BigDecimal.ZERO
|
||||
|
||||
val isSelectionValid: Boolean = if (isCustomAmountFocused) !isCustomAmountTooSmall else selectedBoost != null
|
||||
val shouldDisplayCustomAmountTooSmallError: Boolean = isCustomAmountTooSmall && !isCustomAmountZero
|
||||
}
|
||||
|
||||
data class MonthlyDonationState(
|
||||
|
||||
@@ -214,6 +214,15 @@ class DonateToSignalViewModel(
|
||||
}
|
||||
)
|
||||
|
||||
oneTimeDonationDisposables += oneTimeDonationRepository.getMinimumDonationAmounts().subscribeBy(
|
||||
onSuccess = { amountMap ->
|
||||
store.update { it.copy(oneTimeDonationState = it.oneTimeDonationState.copy(minimumDonationAmounts = amountMap)) }
|
||||
},
|
||||
onError = {
|
||||
Log.w(TAG, "Could not load minimum custom donation amounts.", it)
|
||||
}
|
||||
)
|
||||
|
||||
val boosts: Observable<Map<Currency, List<Boost>>> = oneTimeDonationRepository.getBoosts().toObservable()
|
||||
val oneTimeCurrency: Observable<Currency> = SignalStore.donationsValues().observableOneTimeCurrency
|
||||
|
||||
|
||||
Reference in New Issue
Block a user