From ae7a03bc8fb7c912c2e17d6a52e22dd2d8a4d8e8 Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Tue, 23 Nov 2021 16:14:40 -0500 Subject: [PATCH] Improve boost expiration UI when you're also a sustainer. --- .../ExpiredBadgeBottomSheetDialogFragment.kt | 20 ++++++++++++++++--- .../settings/app/AppSettingsActivity.kt | 7 ++++++- .../securesms/keyvalue/DonationsValues.kt | 17 ++++++++++++---- app/src/main/res/values/strings.xml | 6 ++++-- 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/badges/self/expired/ExpiredBadgeBottomSheetDialogFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/badges/self/expired/ExpiredBadgeBottomSheetDialogFragment.kt index 03ac92bb3..3b532daf0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/badges/self/expired/ExpiredBadgeBottomSheetDialogFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/badges/self/expired/ExpiredBadgeBottomSheetDialogFragment.kt @@ -11,6 +11,7 @@ import org.thoughtcrime.securesms.components.settings.DSLSettingsBottomSheetFrag import org.thoughtcrime.securesms.components.settings.DSLSettingsText import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity import org.thoughtcrime.securesms.components.settings.configure +import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.util.BottomSheetUtil /** @@ -27,6 +28,7 @@ class ExpiredBadgeBottomSheetDialogFragment : DSLSettingsBottomSheetFragment( private fun getConfiguration(): DSLConfiguration { val badge: Badge = ExpiredBadgeBottomSheetDialogFragmentArgs.fromBundle(requireArguments()).badge + val isLikelyASustainer = SignalStore.donationsValues().isLikelyASustainer() return configure { customPref(ExpiredBadge.Model(badge)) @@ -60,7 +62,11 @@ class ExpiredBadgeBottomSheetDialogFragment : DSLSettingsBottomSheetFragment( noPadTextPref( DSLSettingsText.from( if (badge.isBoost()) { - R.string.ExpiredBadgeBottomSheetDialogFragment__to_continue_supporting_technology + if (isLikelyASustainer) { + R.string.ExpiredBadgeBottomSheetDialogFragment__you_can_reactivate + } else { + R.string.ExpiredBadgeBottomSheetDialogFragment__to_continue_supporting_technology + } } else { R.string.ExpiredBadgeBottomSheetDialogFragment__you_can }, @@ -73,14 +79,22 @@ class ExpiredBadgeBottomSheetDialogFragment : DSLSettingsBottomSheetFragment( primaryButton( text = DSLSettingsText.from( if (badge.isBoost()) { - R.string.ExpiredBadgeBottomSheetDialogFragment__become_a_sustainer + if (isLikelyASustainer) { + R.string.ExpiredBadgeBottomSheetDialogFragment__add_a_boost + } else { + R.string.ExpiredBadgeBottomSheetDialogFragment__become_a_sustainer + } } else { R.string.ExpiredBadgeBottomSheetDialogFragment__renew_subscription } ), onClick = { dismiss() - requireActivity().startActivity(AppSettingsActivity.subscriptions(requireContext())) + if (isLikelyASustainer) { + requireActivity().startActivity(AppSettingsActivity.boost(requireContext())) + } else { + requireActivity().startActivity(AppSettingsActivity.subscriptions(requireContext())) + } } ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsActivity.kt index 54c403cd9..fabe41425 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsActivity.kt @@ -48,6 +48,7 @@ class AppSettingsActivity : DSLSettingsActivity(), DonationPaymentComponent { StartLocation.NOTIFICATIONS -> AppSettingsFragmentDirections.actionDirectToNotificationsSettingsFragment() StartLocation.CHANGE_NUMBER -> AppSettingsFragmentDirections.actionDirectToChangeNumberFragment() StartLocation.SUBSCRIPTIONS -> AppSettingsFragmentDirections.actionDirectToSubscriptions() + StartLocation.BOOST -> AppSettingsFragmentDirections.actionAppSettingsFragmentToBoostsFragment() StartLocation.MANAGE_SUBSCRIPTIONS -> AppSettingsFragmentDirections.actionDirectToManageDonations() } } @@ -124,6 +125,9 @@ class AppSettingsActivity : DSLSettingsActivity(), DonationPaymentComponent { @JvmStatic fun subscriptions(context: Context): Intent = getIntentForStartLocation(context, StartLocation.SUBSCRIPTIONS) + @JvmStatic + fun boost(context: Context): Intent = getIntentForStartLocation(context, StartLocation.BOOST) + @JvmStatic fun manageSubscriptions(context: Context): Intent = getIntentForStartLocation(context, StartLocation.MANAGE_SUBSCRIPTIONS) @@ -142,7 +146,8 @@ class AppSettingsActivity : DSLSettingsActivity(), DonationPaymentComponent { NOTIFICATIONS(4), CHANGE_NUMBER(5), SUBSCRIPTIONS(6), - MANAGE_SUBSCRIPTIONS(7); + BOOST(7), + MANAGE_SUBSCRIPTIONS(8); companion object { fun fromCode(code: Int?): StartLocation { diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/DonationsValues.kt b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/DonationsValues.kt index bfd2b6a9a..d54258a4c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/DonationsValues.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/DonationsValues.kt @@ -15,6 +15,7 @@ import org.whispersystems.signalservice.api.subscriptions.IdempotencyKey import org.whispersystems.signalservice.api.subscriptions.SubscriberId import java.util.Currency import java.util.Locale +import java.util.concurrent.TimeUnit internal class DonationsValues internal constructor(store: KeyValueStore) : SignalStoreValues(store) { @@ -25,7 +26,7 @@ internal class DonationsValues internal constructor(store: KeyValueStore) : Sign private const val KEY_CURRENCY_CODE_BOOST = "donation.currency.code.boost" private const val KEY_SUBSCRIBER_ID_PREFIX = "donation.subscriber.id." private const val KEY_LAST_KEEP_ALIVE_LAUNCH = "donation.last.successful.ping" - private const val KEY_LAST_END_OF_PERIOD = "donation.last.end.of.period" + private const val KEY_LAST_END_OF_PERIOD_SECONDS = "donation.last.end.of.period" private const val EXPIRED_BADGE = "donation.expired.badge" private const val USER_MANUALLY_CANCELLED = "donation.user.manually.cancelled" private const val KEY_LEVEL_OPERATION_PREFIX = "donation.level.operation." @@ -40,7 +41,7 @@ internal class DonationsValues internal constructor(store: KeyValueStore) : Sign override fun getKeysToIncludeInBackup(): MutableList = mutableListOf( KEY_CURRENCY_CODE_BOOST, KEY_LAST_KEEP_ALIVE_LAUNCH, - KEY_LAST_END_OF_PERIOD, + KEY_LAST_END_OF_PERIOD_SECONDS, SHOULD_CANCEL_SUBSCRIPTION_BEFORE_NEXT_SUBSCRIBE_ATTEMPT ) @@ -175,11 +176,19 @@ internal class DonationsValues internal constructor(store: KeyValueStore) : Sign } fun getLastEndOfPeriod(): Long { - return getLong(KEY_LAST_END_OF_PERIOD, 0L) + return getLong(KEY_LAST_END_OF_PERIOD_SECONDS, 0L) } fun setLastEndOfPeriod(timestamp: Long) { - putLong(KEY_LAST_END_OF_PERIOD, timestamp) + putLong(KEY_LAST_END_OF_PERIOD_SECONDS, timestamp) + } + + /** + * True if the local user is likely a sustainer, otherwise false. Note the term 'likely', because this is based on cached data. Any serious decisions that + * rely on this should make a network request to determine subscription status. + */ + fun isLikelyASustainer(): Boolean { + return TimeUnit.SECONDS.toMillis(getLastEndOfPeriod()) > System.currentTimeMillis() } fun isUserManuallyCancelled(): Boolean { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7162a8a15..f471c40a9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3990,9 +3990,11 @@ Your Badge has Expired Badge expired Subscription cancelled - Your Boost badge has expired, and is no longer visible to others on your profile. + Your Boost badge has expired and is no longer visible to others on your profile. + You can reactivate your Boost badge for another 30 days with a one-time contribution. To continue supporting technology that is built for you, please consider becoming a monthly Sustainer. - Become a sustainer + Become a Sustainer + Add a Boost Not now Your Sustainer subscription was automatically cancelled because you were inactive for too long. Your %1$s badge is no longer visible on your profile. You can keep using Signal but to support the app and reactivate your badge, renew now.