kopia lustrzana https://github.com/ryukoposting/Signal-Android
Implement checks for badge redemption progress for subscriptions.
rodzic
16ae2c870f
commit
b0f43535c6
|
@ -241,8 +241,8 @@ class BoostFragment : DSLSettingsBottomSheetFragment(
|
||||||
if (throwable is DonationExceptions.TimedOutWaitingForTokenRedemption) {
|
if (throwable is DonationExceptions.TimedOutWaitingForTokenRedemption) {
|
||||||
Log.w(TAG, "Timed out while redeeming token", throwable, true)
|
Log.w(TAG, "Timed out while redeeming token", throwable, true)
|
||||||
MaterialAlertDialogBuilder(requireContext())
|
MaterialAlertDialogBuilder(requireContext())
|
||||||
.setTitle(R.string.DonationsErrors__redemption_still_pending)
|
.setTitle(R.string.DonationsErrors__still_processing)
|
||||||
.setMessage(R.string.DonationsErrors__you_might_not_see_your_badge_right_away)
|
.setMessage(R.string.DonationsErrors__your_payment_is_still)
|
||||||
.setPositiveButton(android.R.string.ok) { dialog, _ ->
|
.setPositiveButton(android.R.string.ok) { dialog, _ ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
findNavController().popBackStack()
|
findNavController().popBackStack()
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
package org.thoughtcrime.securesms.components.settings.app.subscription.manage
|
package org.thoughtcrime.securesms.components.settings.app.subscription.manage
|
||||||
|
|
||||||
|
import android.text.SpannableStringBuilder
|
||||||
|
import android.text.method.LinkMovementMethod
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.widget.ProgressBar
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import org.thoughtcrime.securesms.R
|
import org.thoughtcrime.securesms.R
|
||||||
import org.thoughtcrime.securesms.badges.BadgeImageView
|
import org.thoughtcrime.securesms.badges.BadgeImageView
|
||||||
|
@ -12,6 +16,8 @@ import org.thoughtcrime.securesms.subscription.Subscription
|
||||||
import org.thoughtcrime.securesms.util.DateUtils
|
import org.thoughtcrime.securesms.util.DateUtils
|
||||||
import org.thoughtcrime.securesms.util.MappingAdapter
|
import org.thoughtcrime.securesms.util.MappingAdapter
|
||||||
import org.thoughtcrime.securesms.util.MappingViewHolder
|
import org.thoughtcrime.securesms.util.MappingViewHolder
|
||||||
|
import org.thoughtcrime.securesms.util.SpanUtil
|
||||||
|
import org.thoughtcrime.securesms.util.visible
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,7 +29,9 @@ object ActiveSubscriptionPreference {
|
||||||
class Model(
|
class Model(
|
||||||
val subscription: Subscription,
|
val subscription: Subscription,
|
||||||
val onAddBoostClick: () -> Unit,
|
val onAddBoostClick: () -> Unit,
|
||||||
val renewalTimestamp: Long = -1L
|
val renewalTimestamp: Long = -1L,
|
||||||
|
val redemptionState: ManageDonationsState.SubscriptionRedemptionState,
|
||||||
|
val onContactSupport: () -> Unit
|
||||||
) : PreferenceModel<Model>() {
|
) : PreferenceModel<Model>() {
|
||||||
override fun areItemsTheSame(newItem: Model): Boolean {
|
override fun areItemsTheSame(newItem: Model): Boolean {
|
||||||
return subscription.id == newItem.subscription.id
|
return subscription.id == newItem.subscription.id
|
||||||
|
@ -32,7 +40,8 @@ object ActiveSubscriptionPreference {
|
||||||
override fun areContentsTheSame(newItem: Model): Boolean {
|
override fun areContentsTheSame(newItem: Model): Boolean {
|
||||||
return super.areContentsTheSame(newItem) &&
|
return super.areContentsTheSame(newItem) &&
|
||||||
subscription == newItem.subscription &&
|
subscription == newItem.subscription &&
|
||||||
renewalTimestamp == newItem.renewalTimestamp
|
renewalTimestamp == newItem.renewalTimestamp &&
|
||||||
|
redemptionState == newItem.redemptionState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +52,7 @@ object ActiveSubscriptionPreference {
|
||||||
val price: TextView = itemView.findViewById(R.id.my_support_price)
|
val price: TextView = itemView.findViewById(R.id.my_support_price)
|
||||||
val expiry: TextView = itemView.findViewById(R.id.my_support_expiry)
|
val expiry: TextView = itemView.findViewById(R.id.my_support_expiry)
|
||||||
val boost: MaterialButton = itemView.findViewById(R.id.my_support_boost)
|
val boost: MaterialButton = itemView.findViewById(R.id.my_support_boost)
|
||||||
|
val progress: ProgressBar = itemView.findViewById(R.id.my_support_progress)
|
||||||
|
|
||||||
override fun bind(model: Model) {
|
override fun bind(model: Model) {
|
||||||
badge.setBadge(model.subscription.badge)
|
badge.setBadge(model.subscription.badge)
|
||||||
|
@ -56,7 +66,20 @@ object ActiveSubscriptionPreference {
|
||||||
FiatMoneyUtil.formatOptions()
|
FiatMoneyUtil.formatOptions()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
expiry.movementMethod = LinkMovementMethod.getInstance()
|
||||||
|
|
||||||
|
when (model.redemptionState) {
|
||||||
|
ManageDonationsState.SubscriptionRedemptionState.NONE -> presentRenewalState(model)
|
||||||
|
ManageDonationsState.SubscriptionRedemptionState.IN_PROGRESS -> presentInProgressState()
|
||||||
|
ManageDonationsState.SubscriptionRedemptionState.FAILED -> presentFailureState(model)
|
||||||
|
}
|
||||||
|
|
||||||
|
boost.setOnClickListener {
|
||||||
|
model.onAddBoostClick()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun presentRenewalState(model: Model) {
|
||||||
expiry.text = context.getString(
|
expiry.text = context.getString(
|
||||||
R.string.MySupportPreference__renews_s,
|
R.string.MySupportPreference__renews_s,
|
||||||
DateUtils.formatDateWithYear(
|
DateUtils.formatDateWithYear(
|
||||||
|
@ -64,10 +87,27 @@ object ActiveSubscriptionPreference {
|
||||||
model.renewalTimestamp
|
model.renewalTimestamp
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
badge.alpha = 1f
|
||||||
boost.setOnClickListener {
|
progress.visible = false
|
||||||
model.onAddBoostClick()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun presentInProgressState() {
|
||||||
|
expiry.text = context.getString(R.string.MySupportPreference__processing_transaction)
|
||||||
|
badge.alpha = 0.2f
|
||||||
|
progress.visible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun presentFailureState(model: Model) {
|
||||||
|
expiry.text = SpannableStringBuilder(context.getString(R.string.MySupportPreference__couldnt_add_badge))
|
||||||
|
.append(" ")
|
||||||
|
.append(
|
||||||
|
SpanUtil.clickable(
|
||||||
|
context.getString(R.string.MySupportPreference__please_contact_support),
|
||||||
|
ContextCompat.getColor(context, R.color.signal_accent_primary)
|
||||||
|
) { model.onContactSupport() }
|
||||||
|
)
|
||||||
|
badge.alpha = 0.2f
|
||||||
|
progress.visible = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,12 @@ import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
|
||||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
|
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
|
||||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsIcon
|
import org.thoughtcrime.securesms.components.settings.DSLSettingsIcon
|
||||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
||||||
|
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity
|
||||||
import org.thoughtcrime.securesms.components.settings.app.subscription.SubscriptionsRepository
|
import org.thoughtcrime.securesms.components.settings.app.subscription.SubscriptionsRepository
|
||||||
import org.thoughtcrime.securesms.components.settings.configure
|
import org.thoughtcrime.securesms.components.settings.configure
|
||||||
import org.thoughtcrime.securesms.components.settings.models.IndeterminateLoadingCircle
|
import org.thoughtcrime.securesms.components.settings.models.IndeterminateLoadingCircle
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||||
|
import org.thoughtcrime.securesms.help.HelpFragment
|
||||||
import org.thoughtcrime.securesms.subscription.Subscription
|
import org.thoughtcrime.securesms.subscription.Subscription
|
||||||
import org.thoughtcrime.securesms.util.LifecycleDisposable
|
import org.thoughtcrime.securesms.util.LifecycleDisposable
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
@ -114,7 +116,12 @@ class ManageDonationsFragment : DSLSettingsFragment() {
|
||||||
onAddBoostClick = {
|
onAddBoostClick = {
|
||||||
findNavController().navigate(ManageDonationsFragmentDirections.actionManageDonationsFragmentToBoosts())
|
findNavController().navigate(ManageDonationsFragmentDirections.actionManageDonationsFragmentToBoosts())
|
||||||
},
|
},
|
||||||
renewalTimestamp = TimeUnit.SECONDS.toMillis(activeSubscription.activeSubscription.endOfCurrentPeriod)
|
renewalTimestamp = TimeUnit.SECONDS.toMillis(activeSubscription.activeSubscription.endOfCurrentPeriod),
|
||||||
|
redemptionState = state.subscriptionRedemptionState,
|
||||||
|
onContactSupport = {
|
||||||
|
requireActivity().finish()
|
||||||
|
requireActivity().startActivity(AppSettingsActivity.help(requireContext(), HelpFragment.DONATION_INDEX))
|
||||||
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -132,6 +139,7 @@ class ManageDonationsFragment : DSLSettingsFragment() {
|
||||||
clickPref(
|
clickPref(
|
||||||
title = DSLSettingsText.from(R.string.ManageDonationsFragment__manage_subscription),
|
title = DSLSettingsText.from(R.string.ManageDonationsFragment__manage_subscription),
|
||||||
icon = DSLSettingsIcon.from(R.drawable.ic_person_white_24dp),
|
icon = DSLSettingsIcon.from(R.drawable.ic_person_white_24dp),
|
||||||
|
isEnabled = state.subscriptionRedemptionState != ManageDonationsState.SubscriptionRedemptionState.IN_PROGRESS,
|
||||||
onClick = {
|
onClick = {
|
||||||
findNavController().navigate(ManageDonationsFragmentDirections.actionManageDonationsFragmentToSubscribeFragment())
|
findNavController().navigate(ManageDonationsFragmentDirections.actionManageDonationsFragmentToSubscribeFragment())
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,18 @@ import org.whispersystems.signalservice.api.subscriptions.ActiveSubscription
|
||||||
data class ManageDonationsState(
|
data class ManageDonationsState(
|
||||||
val featuredBadge: Badge? = null,
|
val featuredBadge: Badge? = null,
|
||||||
val transactionState: TransactionState = TransactionState.Init,
|
val transactionState: TransactionState = TransactionState.Init,
|
||||||
val availableSubscriptions: List<Subscription> = emptyList()
|
val availableSubscriptions: List<Subscription> = emptyList(),
|
||||||
|
val subscriptionRedemptionState: SubscriptionRedemptionState = SubscriptionRedemptionState.NONE
|
||||||
) {
|
) {
|
||||||
sealed class TransactionState {
|
sealed class TransactionState {
|
||||||
object Init : TransactionState()
|
object Init : TransactionState()
|
||||||
object InTransaction : TransactionState()
|
object InTransaction : TransactionState()
|
||||||
class NotInTransaction(val activeSubscription: ActiveSubscription) : TransactionState()
|
class NotInTransaction(val activeSubscription: ActiveSubscription) : TransactionState()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class SubscriptionRedemptionState {
|
||||||
|
NONE,
|
||||||
|
IN_PROGRESS,
|
||||||
|
FAILED
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import io.reactivex.rxjava3.kotlin.subscribeBy
|
||||||
import io.reactivex.rxjava3.subjects.PublishSubject
|
import io.reactivex.rxjava3.subjects.PublishSubject
|
||||||
import org.signal.core.util.logging.Log
|
import org.signal.core.util.logging.Log
|
||||||
import org.thoughtcrime.securesms.components.settings.app.subscription.SubscriptionsRepository
|
import org.thoughtcrime.securesms.components.settings.app.subscription.SubscriptionsRepository
|
||||||
|
import org.thoughtcrime.securesms.jobmanager.JobTracker
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
import org.thoughtcrime.securesms.subscription.LevelUpdate
|
import org.thoughtcrime.securesms.subscription.LevelUpdate
|
||||||
import org.thoughtcrime.securesms.util.livedata.Store
|
import org.thoughtcrime.securesms.util.livedata.Store
|
||||||
|
@ -44,6 +45,22 @@ class ManageDonationsViewModel(
|
||||||
val levelUpdateOperationEdges: Observable<Boolean> = LevelUpdate.isProcessing.distinctUntilChanged()
|
val levelUpdateOperationEdges: Observable<Boolean> = LevelUpdate.isProcessing.distinctUntilChanged()
|
||||||
val activeSubscription: Single<ActiveSubscription> = subscriptionsRepository.getActiveSubscription()
|
val activeSubscription: Single<ActiveSubscription> = subscriptionsRepository.getActiveSubscription()
|
||||||
|
|
||||||
|
disposables += SubscriptionRedemptionJobWatcher.watch().subscribeBy { jobStateOptional ->
|
||||||
|
store.update { manageDonationsState ->
|
||||||
|
manageDonationsState.copy(
|
||||||
|
subscriptionRedemptionState = jobStateOptional.transform { jobState ->
|
||||||
|
when (jobState) {
|
||||||
|
JobTracker.JobState.PENDING -> ManageDonationsState.SubscriptionRedemptionState.IN_PROGRESS
|
||||||
|
JobTracker.JobState.RUNNING -> ManageDonationsState.SubscriptionRedemptionState.IN_PROGRESS
|
||||||
|
JobTracker.JobState.SUCCESS -> ManageDonationsState.SubscriptionRedemptionState.NONE
|
||||||
|
JobTracker.JobState.FAILURE -> ManageDonationsState.SubscriptionRedemptionState.FAILED
|
||||||
|
JobTracker.JobState.IGNORED -> ManageDonationsState.SubscriptionRedemptionState.NONE
|
||||||
|
}
|
||||||
|
}.or(ManageDonationsState.SubscriptionRedemptionState.NONE)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
disposables += levelUpdateOperationEdges.flatMapSingle { isProcessing ->
|
disposables += levelUpdateOperationEdges.flatMapSingle { isProcessing ->
|
||||||
if (isProcessing) {
|
if (isProcessing) {
|
||||||
Single.just(ManageDonationsState.TransactionState.InTransaction)
|
Single.just(ManageDonationsState.TransactionState.InTransaction)
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
package org.thoughtcrime.securesms.components.settings.app.subscription.manage
|
||||||
|
|
||||||
|
import io.reactivex.rxjava3.core.Observable
|
||||||
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||||
|
import org.thoughtcrime.securesms.jobmanager.JobTracker
|
||||||
|
import org.thoughtcrime.securesms.jobs.DonationReceiptRedemptionJob
|
||||||
|
import org.thoughtcrime.securesms.jobs.SubscriptionReceiptRequestResponseJob
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
|
import org.whispersystems.libsignal.util.guava.Optional
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows observer to poll for the status of the latest pending, running, or completed redemption job for subscriptions.
|
||||||
|
*/
|
||||||
|
object SubscriptionRedemptionJobWatcher {
|
||||||
|
fun watch(): Observable<Optional<JobTracker.JobState>> = Observable.interval(0, 5, TimeUnit.SECONDS).map {
|
||||||
|
val redemptionJobState: JobTracker.JobState? = ApplicationDependencies.getJobManager().getFirstMatchingJobState {
|
||||||
|
it.factoryKey == DonationReceiptRedemptionJob.KEY && it.parameters.queue == DonationReceiptRedemptionJob.SUBSCRIPTION_QUEUE
|
||||||
|
}
|
||||||
|
|
||||||
|
val receiptJobState: JobTracker.JobState? = ApplicationDependencies.getJobManager().getFirstMatchingJobState {
|
||||||
|
it.factoryKey == SubscriptionReceiptRequestResponseJob.KEY && it.parameters.queue == DonationReceiptRedemptionJob.SUBSCRIPTION_QUEUE
|
||||||
|
}
|
||||||
|
|
||||||
|
val jobState: JobTracker.JobState? = redemptionJobState ?: receiptJobState
|
||||||
|
|
||||||
|
if (jobState == null && SignalStore.donationsValues().getSubscriptionRedemptionFailed()) {
|
||||||
|
Optional.of(JobTracker.JobState.FAILURE)
|
||||||
|
} else {
|
||||||
|
Optional.fromNullable(jobState)
|
||||||
|
}
|
||||||
|
}.distinctUntilChanged()
|
||||||
|
}
|
|
@ -275,12 +275,12 @@ class SubscribeFragment : DSLSettingsFragment(
|
||||||
if (throwable is DonationExceptions.TimedOutWaitingForTokenRedemption) {
|
if (throwable is DonationExceptions.TimedOutWaitingForTokenRedemption) {
|
||||||
Log.w(TAG, "Timeout occurred while redeeming token", throwable, true)
|
Log.w(TAG, "Timeout occurred while redeeming token", throwable, true)
|
||||||
MaterialAlertDialogBuilder(requireContext())
|
MaterialAlertDialogBuilder(requireContext())
|
||||||
.setTitle(R.string.DonationsErrors__redemption_still_pending)
|
.setTitle(R.string.DonationsErrors__still_processing)
|
||||||
.setMessage(R.string.DonationsErrors__you_might_not_see_your_badge_right_away)
|
.setMessage(R.string.DonationsErrors__your_payment)
|
||||||
.setPositiveButton(android.R.string.ok) { dialog, _ ->
|
.setPositiveButton(android.R.string.ok) { dialog, _ ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
requireActivity().finish()
|
requireActivity().finish()
|
||||||
requireActivity().startActivity(AppSettingsActivity.subscriptions(requireContext()))
|
requireActivity().startActivity(AppSettingsActivity.manageSubscriptions(requireContext()))
|
||||||
}
|
}
|
||||||
.show()
|
.show()
|
||||||
} else if (throwable is DonationExceptions.SetupFailed) {
|
} else if (throwable is DonationExceptions.SetupFailed) {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import org.whispersystems.signalservice.internal.EmptyResponse;
|
||||||
import org.whispersystems.signalservice.internal.ServiceResponse;
|
import org.whispersystems.signalservice.internal.ServiceResponse;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,6 +24,7 @@ import java.util.concurrent.TimeUnit;
|
||||||
public class DonationReceiptRedemptionJob extends BaseJob {
|
public class DonationReceiptRedemptionJob extends BaseJob {
|
||||||
private static final String TAG = Log.tag(DonationReceiptRedemptionJob.class);
|
private static final String TAG = Log.tag(DonationReceiptRedemptionJob.class);
|
||||||
|
|
||||||
|
public static final String SUBSCRIPTION_QUEUE = "ReceiptRedemption";
|
||||||
public static final String KEY = "DonationReceiptRedemptionJob";
|
public static final String KEY = "DonationReceiptRedemptionJob";
|
||||||
public static final String INPUT_RECEIPT_CREDENTIAL_PRESENTATION = "data.receipt.credential.presentation";
|
public static final String INPUT_RECEIPT_CREDENTIAL_PRESENTATION = "data.receipt.credential.presentation";
|
||||||
|
|
||||||
|
@ -31,7 +33,7 @@ public class DonationReceiptRedemptionJob extends BaseJob {
|
||||||
new Job.Parameters
|
new Job.Parameters
|
||||||
.Builder()
|
.Builder()
|
||||||
.addConstraint(NetworkConstraint.KEY)
|
.addConstraint(NetworkConstraint.KEY)
|
||||||
.setQueue("ReceiptRedemption")
|
.setQueue(SUBSCRIPTION_QUEUE)
|
||||||
.setMaxAttempts(Parameters.UNLIMITED)
|
.setMaxAttempts(Parameters.UNLIMITED)
|
||||||
.setMaxInstancesForQueue(1)
|
.setMaxInstancesForQueue(1)
|
||||||
.setLifespan(TimeUnit.DAYS.toMillis(7))
|
.setLifespan(TimeUnit.DAYS.toMillis(7))
|
||||||
|
@ -66,6 +68,9 @@ public class DonationReceiptRedemptionJob extends BaseJob {
|
||||||
@Override
|
@Override
|
||||||
public void onFailure() {
|
public void onFailure() {
|
||||||
SubscriptionNotification.RedemptionFailed.INSTANCE.show(context);
|
SubscriptionNotification.RedemptionFailed.INSTANCE.show(context);
|
||||||
|
if (isForSubscription()) {
|
||||||
|
SignalStore.donationsValues().markSubscriptionRedemptionFailed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -103,6 +108,14 @@ public class DonationReceiptRedemptionJob extends BaseJob {
|
||||||
Log.w(TAG, "Encountered a retryable exception", response.getExecutionError().get(), true);
|
Log.w(TAG, "Encountered a retryable exception", response.getExecutionError().get(), true);
|
||||||
throw new RetryableException();
|
throw new RetryableException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isForSubscription()) {
|
||||||
|
SignalStore.donationsValues().clearSubscriptionRedemptionFailed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isForSubscription() {
|
||||||
|
return Objects.equals(getParameters().getQueue(), SUBSCRIPTION_QUEUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -4,6 +4,7 @@ import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
|
import org.signal.core.util.ThreadUtil;
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.signal.zkgroup.InvalidInputException;
|
import org.signal.zkgroup.InvalidInputException;
|
||||||
import org.signal.zkgroup.VerificationFailedException;
|
import org.signal.zkgroup.VerificationFailedException;
|
||||||
|
@ -103,6 +104,7 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
|
||||||
@Override
|
@Override
|
||||||
public void onFailure() {
|
public void onFailure() {
|
||||||
SubscriptionNotification.VerificationFailed.INSTANCE.show(context);
|
SubscriptionNotification.VerificationFailed.INSTANCE.show(context);
|
||||||
|
SignalStore.donationsValues().markSubscriptionRedemptionFailed();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -140,6 +142,10 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
|
||||||
|
|
||||||
if (response.getApplicationError().isPresent()) {
|
if (response.getApplicationError().isPresent()) {
|
||||||
handleApplicationError(response);
|
handleApplicationError(response);
|
||||||
|
|
||||||
|
if (response.getStatus() == 204) {
|
||||||
|
SignalStore.donationsValues().clearSubscriptionRedemptionFailed();
|
||||||
|
}
|
||||||
} else if (response.getResult().isPresent()) {
|
} else if (response.getResult().isPresent()) {
|
||||||
ReceiptCredential receiptCredential = getReceiptCredential(response.getResult().get());
|
ReceiptCredential receiptCredential = getReceiptCredential(response.getResult().get());
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ internal class DonationsValues internal constructor(store: KeyValueStore) : Sign
|
||||||
private const val KEY_LEVEL_OPERATION_PREFIX = "donation.level.operation."
|
private const val KEY_LEVEL_OPERATION_PREFIX = "donation.level.operation."
|
||||||
private const val KEY_LEVEL_HISTORY = "donation.level.history"
|
private const val KEY_LEVEL_HISTORY = "donation.level.history"
|
||||||
private const val DISPLAY_BADGES_ON_PROFILE = "donation.display.badges.on.profile"
|
private const val DISPLAY_BADGES_ON_PROFILE = "donation.display.badges.on.profile"
|
||||||
|
private const val SUBSCRIPTION_REDEMPTION_FAILED = "donation.subscription.redemption.failed"
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFirstEverAppLaunch() = Unit
|
override fun onFirstEverAppLaunch() = Unit
|
||||||
|
@ -197,4 +198,16 @@ internal class DonationsValues internal constructor(store: KeyValueStore) : Sign
|
||||||
fun getDisplayBadgesOnProfile(): Boolean {
|
fun getDisplayBadgesOnProfile(): Boolean {
|
||||||
return getBoolean(DISPLAY_BADGES_ON_PROFILE, false)
|
return getBoolean(DISPLAY_BADGES_ON_PROFILE, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getSubscriptionRedemptionFailed(): Boolean {
|
||||||
|
return getBoolean(SUBSCRIPTION_REDEMPTION_FAILED, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun markSubscriptionRedemptionFailed() {
|
||||||
|
putBoolean(SUBSCRIPTION_REDEMPTION_FAILED, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clearSubscriptionRedemptionFailed() {
|
||||||
|
putBoolean(SUBSCRIPTION_REDEMPTION_FAILED, false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,16 @@
|
||||||
app:layout_constraintTop_toTopOf="@id/my_support_title"
|
app:layout_constraintTop_toTopOf="@id/my_support_title"
|
||||||
tools:src="@drawable/test_gradient" />
|
tools:src="@drawable/test_gradient" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/my_support_progress"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/my_support_badge"
|
||||||
|
app:layout_constraintEnd_toEndOf="@id/my_support_badge"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/my_support_badge"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/my_support_badge" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/my_support_title"
|
android:id="@+id/my_support_title"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
@ -75,10 +85,10 @@
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/my_support_boost"
|
android:id="@+id/my_support_boost"
|
||||||
android:background="@drawable/my_boost_gradient"
|
|
||||||
style="@style/Signal.Widget.Button.Large.Primary"
|
style="@style/Signal.Widget.Button.Large.Primary"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/my_boost_gradient"
|
||||||
android:text="@string/MySupportPreference__add_a_signal_boost"
|
android:text="@string/MySupportPreference__add_a_signal_boost"
|
||||||
app:cornerRadius="0dp"
|
app:cornerRadius="0dp"
|
||||||
app:layout_constraintTop_toBottomOf="@id/my_support_heading_barrier" />
|
app:layout_constraintTop_toBottomOf="@id/my_support_heading_barrier" />
|
||||||
|
|
|
@ -3986,6 +3986,9 @@
|
||||||
<string name="MySupportPreference__add_a_signal_boost">Add a Signal Boost</string>
|
<string name="MySupportPreference__add_a_signal_boost">Add a Signal Boost</string>
|
||||||
<string name="MySupportPreference__s_per_month">%1$s/month</string>
|
<string name="MySupportPreference__s_per_month">%1$s/month</string>
|
||||||
<string name="MySupportPreference__renews_s">Renews %1$s</string>
|
<string name="MySupportPreference__renews_s">Renews %1$s</string>
|
||||||
|
<string name="MySupportPreference__processing_transaction">Processing transaction…</string>
|
||||||
|
<string name="MySupportPreference__couldnt_add_badge">Couldn\'t add badge.</string>
|
||||||
|
<string name="MySupportPreference__please_contact_support">Please contact support.</string>
|
||||||
|
|
||||||
<string name="ExpiredBadgeBottomSheetDialogFragment__your_badge_has_expired">Your Badge has Expired</string>
|
<string name="ExpiredBadgeBottomSheetDialogFragment__your_badge_has_expired">Your Badge has Expired</string>
|
||||||
<string name="ExpiredBadgeBottomSheetDialogFragment__badge_expired">Badge expired</string>
|
<string name="ExpiredBadgeBottomSheetDialogFragment__badge_expired">Badge expired</string>
|
||||||
|
@ -4007,10 +4010,10 @@
|
||||||
<string name="SubscribeFragment__processing_payment">Processing payment…</string>
|
<string name="SubscribeFragment__processing_payment">Processing payment…</string>
|
||||||
<string name="DonationsErrors__payment_failed">Payment failed</string>
|
<string name="DonationsErrors__payment_failed">Payment failed</string>
|
||||||
<string name="DonationsErrors__your_payment">Your payment couldn\'t be processed and you have not been charged. Please try again.</string>
|
<string name="DonationsErrors__your_payment">Your payment couldn\'t be processed and you have not been charged. Please try again.</string>
|
||||||
<string name="DonationsErrors__redemption_still_pending">Redemption still pending</string>
|
<string name="DonationsErrors__still_processing">Still processing</string>
|
||||||
<string name="DonationsErrors__redemption_failed">Redemption failed</string>
|
<string name="DonationsErrors__redemption_failed">Redemption failed</string>
|
||||||
<string name="DonationsErrors__please_contact_support">Please contact support</string>
|
<string name="DonationsErrors__please_contact_support">Please contact support</string>
|
||||||
<string name="DonationsErrors__you_might_not_see_your_badge_right_away">You may not see your badge right away, but we\'re working on it!</string>
|
<string name="DonationsErrors__your_payment_is_still">Your payment is still being processed. This can take a few minutes depending on your connection.</string>
|
||||||
<string name="DonationsErrors__google_pay_unavailable">Google Pay Unavailable</string>
|
<string name="DonationsErrors__google_pay_unavailable">Google Pay Unavailable</string>
|
||||||
<string name="DonationsErrors__you_have_to_set_up_google_pay_to_donate_in_app">You have to set up Google Pay to donate in-app.</string>
|
<string name="DonationsErrors__you_have_to_set_up_google_pay_to_donate_in_app">You have to set up Google Pay to donate in-app.</string>
|
||||||
<string name="DonationsErrors__failed_to_cancel_subscription">Failed to cancel subscription</string>
|
<string name="DonationsErrors__failed_to_cancel_subscription">Failed to cancel subscription</string>
|
||||||
|
|
Ładowanie…
Reference in New Issue