From 6b94fc82eb550a2231f1dda70b0f310f7fe4a715 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Thu, 11 Nov 2021 14:59:30 -0400 Subject: [PATCH] Add and sync displayBadgesOnProfile Flag. --- .../securesms/badges/BadgeRepository.kt | 10 +++++++++- .../securesms/badges/models/Badge.kt | 4 ---- .../self/overview/BadgesOverviewViewModel.kt | 3 ++- .../subscription/DonationPaymentRepository.kt | 16 +++++++++++++++- .../subscription/currency/SetCurrencyFragment.kt | 7 +++++++ .../currency/SetCurrencyViewModel.kt | 3 --- .../subscription/subscribe/SubscribeViewModel.kt | 3 +-- ...nksForYourSupportBottomSheetDialogFragment.kt | 3 ++- .../jobs/DonationReceiptRedemptionJob.java | 5 ++++- .../securesms/jobs/RefreshOwnProfileJob.java | 7 +++++-- .../securesms/keyvalue/DonationsValues.kt | 9 +++++++++ .../storage/AccountRecordProcessor.java | 12 ++++++++---- .../securesms/storage/StorageSyncHelper.java | 2 ++ .../api/storage/SignalAccountRecord.java | 13 +++++++++++++ .../service/src/main/proto/StorageService.proto | 1 + 15 files changed, 78 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/badges/BadgeRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/badges/BadgeRepository.kt index 92e100bd6..4d7972e21 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/badges/BadgeRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/badges/BadgeRepository.kt @@ -6,7 +6,9 @@ import io.reactivex.rxjava3.schedulers.Schedulers import org.thoughtcrime.securesms.badges.models.Badge import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.RecipientDatabase +import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.recipients.Recipient +import org.thoughtcrime.securesms.storage.StorageSyncHelper import org.thoughtcrime.securesms.util.ProfileUtil class BadgeRepository(context: Context) { @@ -17,10 +19,16 @@ class BadgeRepository(context: Context) { displayBadgesOnProfile: Boolean, selfBadges: List = Recipient.self().badges ): Completable = Completable.fromAction { + val recipientDatabase: RecipientDatabase = DatabaseFactory.getRecipientDatabase(context) + + SignalStore.donationsValues().setDisplayBadgesOnProfile(displayBadgesOnProfile) + + recipientDatabase.markNeedsSync(Recipient.self().id) + StorageSyncHelper.scheduleSyncForDataChange() + val badges = selfBadges.map { it.copy(visible = displayBadgesOnProfile) } ProfileUtil.uploadProfileWithBadges(context, badges) - val recipientDatabase: RecipientDatabase = DatabaseFactory.getRecipientDatabase(context) recipientDatabase.setBadges(Recipient.self().id, badges) }.subscribeOn(Schedulers.io()) diff --git a/app/src/main/java/org/thoughtcrime/securesms/badges/models/Badge.kt b/app/src/main/java/org/thoughtcrime/securesms/badges/models/Badge.kt index 79e959357..d28f91b26 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/badges/models/Badge.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/badges/models/Badge.kt @@ -36,10 +36,6 @@ data class Badge( val visible: Boolean, ) : Parcelable, Key { - fun setVisible(): Badge { - return copy(visible = true) - } - fun isExpired(): Boolean = expirationTimestamp < System.currentTimeMillis() && expirationTimestamp > 0 fun isBoost(): Boolean = id == BOOST_BADGE_ID diff --git a/app/src/main/java/org/thoughtcrime/securesms/badges/self/overview/BadgesOverviewViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/badges/self/overview/BadgesOverviewViewModel.kt index b5a0b9fad..1ecfbc312 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/badges/self/overview/BadgesOverviewViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/badges/self/overview/BadgesOverviewViewModel.kt @@ -13,6 +13,7 @@ import io.reactivex.rxjava3.subjects.PublishSubject import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.badges.BadgeRepository import org.thoughtcrime.securesms.components.settings.app.subscription.SubscriptionsRepository +import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.util.livedata.Store import org.whispersystems.libsignal.util.guava.Optional @@ -36,7 +37,7 @@ class BadgesOverviewViewModel( state.copy( stage = if (state.stage == BadgesOverviewState.Stage.INIT) BadgesOverviewState.Stage.READY else state.stage, allUnlockedBadges = recipient.badges, - displayBadgesOnProfile = recipient.badges.firstOrNull()?.visible == true, + displayBadgesOnProfile = SignalStore.donationsValues().getDisplayBadgesOnProfile(), featuredBadge = recipient.featuredBadge ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/DonationPaymentRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/DonationPaymentRepository.kt index c8af199ab..e73cde219 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/DonationPaymentRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/DonationPaymentRepository.kt @@ -11,17 +11,20 @@ import io.reactivex.rxjava3.core.Completable import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.schedulers.Schedulers +import org.signal.core.util.concurrent.SignalExecutors import org.signal.core.util.logging.Log import org.signal.core.util.money.FiatMoney import org.signal.donations.GooglePayApi import org.signal.donations.GooglePayPaymentSource import org.signal.donations.StripeApi +import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.jobmanager.JobTracker import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint import org.thoughtcrime.securesms.jobs.BoostReceiptRequestResponseJob import org.thoughtcrime.securesms.jobs.SubscriptionReceiptRequestResponseJob import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.storage.StorageSyncHelper import org.thoughtcrime.securesms.subscription.LevelUpdate import org.thoughtcrime.securesms.subscription.LevelUpdateOperation @@ -60,6 +63,17 @@ class DonationPaymentRepository(activity: Activity) : StripeApi.PaymentIntentFet fun isGooglePayAvailable(): Completable = googlePayApi.queryIsReadyToPay() + fun scheduleSyncForAccountRecordChange() { + SignalExecutors.BOUNDED.execute { + scheduleSyncForAccountRecordChangeSync() + } + } + + fun scheduleSyncForAccountRecordChangeSync() { + DatabaseFactory.getRecipientDatabase(application).markNeedsSync(Recipient.self().id) + StorageSyncHelper.scheduleSyncForDataChange() + } + fun internetConnectionObserver(): Observable = Observable.create { val observer = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { @@ -124,7 +138,7 @@ class DonationPaymentRepository(activity: Activity) : StripeApi.PaymentIntentFet .donationsValues() .setSubscriber(Subscriber(subscriberId, SignalStore.donationsValues().getSubscriptionCurrency().currencyCode)) - StorageSyncHelper.scheduleSyncForDataChange() + scheduleSyncForAccountRecordChangeSync() } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/currency/SetCurrencyFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/currency/SetCurrencyFragment.kt index 0e38a07fc..4c316eab7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/currency/SetCurrencyFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/currency/SetCurrencyFragment.kt @@ -5,7 +5,9 @@ import org.thoughtcrime.securesms.components.settings.DSLConfiguration import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter import org.thoughtcrime.securesms.components.settings.DSLSettingsBottomSheetFragment import org.thoughtcrime.securesms.components.settings.DSLSettingsText +import org.thoughtcrime.securesms.components.settings.app.subscription.DonationPaymentComponent import org.thoughtcrime.securesms.components.settings.configure +import org.thoughtcrime.securesms.keyboard.findListener import java.util.Locale /** @@ -13,6 +15,8 @@ import java.util.Locale */ class SetCurrencyFragment : DSLSettingsBottomSheetFragment() { + private lateinit var donationPaymentComponent: DonationPaymentComponent + private val viewModel: SetCurrencyViewModel by viewModels( factoryProducer = { val args = SetCurrencyFragmentArgs.fromBundle(requireArguments()) @@ -21,6 +25,8 @@ class SetCurrencyFragment : DSLSettingsBottomSheetFragment() { ) override fun bindAdapter(adapter: DSLSettingsAdapter) { + donationPaymentComponent = findListener()!! + viewModel.state.observe(viewLifecycleOwner) { state -> adapter.submitList(getConfiguration(state).toMappingModelList()) } @@ -34,6 +40,7 @@ class SetCurrencyFragment : DSLSettingsBottomSheetFragment() { summary = DSLSettingsText.from(currency.currencyCode), onClick = { viewModel.setSelectedCurrency(currency.currencyCode) + donationPaymentComponent.donationPaymentRepository.scheduleSyncForAccountRecordChange() dismissAllowingStateLoss() } ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/currency/SetCurrencyViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/currency/SetCurrencyViewModel.kt index 5cb5e3023..596af1452 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/currency/SetCurrencyViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/currency/SetCurrencyViewModel.kt @@ -6,7 +6,6 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import org.thoughtcrime.securesms.BuildConfig import org.thoughtcrime.securesms.keyvalue.SignalStore -import org.thoughtcrime.securesms.storage.StorageSyncHelper import org.thoughtcrime.securesms.subscription.Subscriber import org.thoughtcrime.securesms.util.livedata.Store import org.whispersystems.signalservice.api.subscriptions.SubscriberId @@ -52,8 +51,6 @@ class SetCurrencyViewModel( ) ) } - - StorageSyncHelper.scheduleSyncForDataChange() } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/subscribe/SubscribeViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/subscribe/SubscribeViewModel.kt index efb628511..5d250145a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/subscribe/SubscribeViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/subscribe/SubscribeViewModel.kt @@ -20,7 +20,6 @@ import org.thoughtcrime.securesms.components.settings.app.subscription.DonationE import org.thoughtcrime.securesms.components.settings.app.subscription.DonationPaymentRepository import org.thoughtcrime.securesms.components.settings.app.subscription.SubscriptionsRepository import org.thoughtcrime.securesms.keyvalue.SignalStore -import org.thoughtcrime.securesms.storage.StorageSyncHelper import org.thoughtcrime.securesms.subscription.LevelUpdate import org.thoughtcrime.securesms.subscription.Subscriber import org.thoughtcrime.securesms.subscription.Subscription @@ -105,7 +104,7 @@ class SubscribeViewModel( val usd = PlatformCurrencyUtil.USD val newSubscriber = SignalStore.donationsValues().getSubscriber(usd) ?: Subscriber(SubscriberId.generate(), usd.currencyCode) SignalStore.donationsValues().setSubscriber(newSubscriber) - StorageSyncHelper.scheduleSyncForDataChange() + donationPaymentRepository.scheduleSyncForAccountRecordChange() } } }, diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/thanks/ThanksForYourSupportBottomSheetDialogFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/thanks/ThanksForYourSupportBottomSheetDialogFragment.kt index 1fd7e1682..a641fa883 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/thanks/ThanksForYourSupportBottomSheetDialogFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/thanks/ThanksForYourSupportBottomSheetDialogFragment.kt @@ -22,6 +22,7 @@ import org.thoughtcrime.securesms.badges.BadgeImageView import org.thoughtcrime.securesms.badges.BadgeRepository import org.thoughtcrime.securesms.components.FixedRoundedCornerBottomSheetDialogFragment import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity +import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.util.SpanUtil import org.thoughtcrime.securesms.util.visible @@ -87,7 +88,7 @@ class ThanksForYourSupportBottomSheetDialogFragment : FixedRoundedCornerBottomSh val otherBadges = Recipient.self().badges.filterNot { it.id == args.badge.id } val hasOtherBadges = otherBadges.isNotEmpty() - val displayingBadges = otherBadges.all { it.visible } + val displayingBadges = SignalStore.donationsValues().getDisplayBadgesOnProfile() if (hasOtherBadges && displayingBadges) { switch.isChecked = false diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/DonationReceiptRedemptionJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/DonationReceiptRedemptionJob.java index b085e1850..0654badce 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/DonationReceiptRedemptionJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/DonationReceiptRedemptionJob.java @@ -9,6 +9,7 @@ import org.thoughtcrime.securesms.jobmanager.Data; import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; import org.thoughtcrime.securesms.subscription.SubscriptionNotification; +import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.whispersystems.signalservice.internal.EmptyResponse; import org.whispersystems.signalservice.internal.ServiceResponse; @@ -85,7 +86,9 @@ public class DonationReceiptRedemptionJob extends BaseJob { ReceiptCredentialPresentation presentation = new ReceiptCredentialPresentation(presentationBytes); ServiceResponse response = ApplicationDependencies.getDonationsService() - .redeemReceipt(presentation, false, false) + .redeemReceipt(presentation, + SignalStore.donationsValues().getDisplayBadgesOnProfile(), + false) .blockingGet(); if (response.getApplicationError().isPresent()) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/RefreshOwnProfileJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/RefreshOwnProfileJob.java index 3ba94c606..a24ac2d47 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/RefreshOwnProfileJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/RefreshOwnProfileJob.java @@ -221,10 +221,13 @@ public class RefreshOwnProfileJob extends BaseJob { List appBadges = badges.stream().map(Badges::fromServiceBadge).collect(Collectors.toList()); if (userHasVisibleBadges && userHasInvisibleBadges) { - Log.d(TAG, "Detected mixed visibility of badges. Telling the server to mark them all visible.", true); + boolean displayBadgesOnProfile = SignalStore.donationsValues().getDisplayBadgesOnProfile(); + Log.d(TAG, "Detected mixed visibility of badges. Telling the server to mark them all " + + (displayBadgesOnProfile ? "" : "not") + + " visible.", true); BadgeRepository badgeRepository = new BadgeRepository(context); - badgeRepository.setVisibilityForAllBadges(true, appBadges).blockingSubscribe(); + badgeRepository.setVisibilityForAllBadges(displayBadgesOnProfile, appBadges).blockingSubscribe(); } else { DatabaseFactory.getRecipientDatabase(context) .setBadges(Recipient.self().getId(), appBadges); 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 402b53d9b..50d26883f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/DonationsValues.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/DonationsValues.kt @@ -29,6 +29,7 @@ internal class DonationsValues internal constructor(store: KeyValueStore) : Sign private const val USER_MANUALLY_CANCELLED = "donation.user.manually.cancelled" private const val KEY_LEVEL_OPERATION_PREFIX = "donation.level.operation." private const val KEY_LEVEL_HISTORY = "donation.level.history" + private const val DISPLAY_BADGES_ON_PROFILE = "donation.display.badges.on.profile" } override fun onFirstEverAppLaunch() = Unit @@ -188,4 +189,12 @@ internal class DonationsValues internal constructor(store: KeyValueStore) : Sign fun clearUserManuallyCancelled() { remove(USER_MANUALLY_CANCELLED) } + + fun setDisplayBadgesOnProfile(enabled: Boolean) { + putBoolean(DISPLAY_BADGES_ON_PROFILE, enabled) + } + + fun getDisplayBadgesOnProfile(): Boolean { + return getBoolean(DISPLAY_BADGES_ON_PROFILE, false) + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/storage/AccountRecordProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/storage/AccountRecordProcessor.java index e5bbddcd1..2b787428f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/storage/AccountRecordProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/storage/AccountRecordProcessor.java @@ -108,8 +108,9 @@ public class AccountRecordProcessor extends DefaultStorageRecordProcessor defaultReactions = remote.getDefaultReactions().size() > 0 ? remote.getDefaultReactions() : local.getDefaultReactions(); - boolean matchesRemote = doParamsMatch(remote, unknownFields, givenName, familyName, avatarUrlPath, profileKey, noteToSelfArchived, noteToSelfForcedUnread, readReceipts, typingIndicators, sealedSenderIndicators, linkPreviews, phoneNumberSharingMode, unlisted, pinnedConversations, preferContactAvatars, payments, universalExpireTimer, primarySendsSms, e164, defaultReactions, subscriber); - boolean matchesLocal = doParamsMatch(local, unknownFields, givenName, familyName, avatarUrlPath, profileKey, noteToSelfArchived, noteToSelfForcedUnread, readReceipts, typingIndicators, sealedSenderIndicators, linkPreviews, phoneNumberSharingMode, unlisted, pinnedConversations, preferContactAvatars, payments, universalExpireTimer, primarySendsSms, e164, defaultReactions, subscriber); + boolean displayBadgesOnProfile = remote.isDisplayBadgesOnProfile(); + boolean matchesRemote = doParamsMatch(remote, unknownFields, givenName, familyName, avatarUrlPath, profileKey, noteToSelfArchived, noteToSelfForcedUnread, readReceipts, typingIndicators, sealedSenderIndicators, linkPreviews, phoneNumberSharingMode, unlisted, pinnedConversations, preferContactAvatars, payments, universalExpireTimer, primarySendsSms, e164, defaultReactions, subscriber, displayBadgesOnProfile); + boolean matchesLocal = doParamsMatch(local, unknownFields, givenName, familyName, avatarUrlPath, profileKey, noteToSelfArchived, noteToSelfForcedUnread, readReceipts, typingIndicators, sealedSenderIndicators, linkPreviews, phoneNumberSharingMode, unlisted, pinnedConversations, preferContactAvatars, payments, universalExpireTimer, primarySendsSms, e164, defaultReactions, subscriber, displayBadgesOnProfile); if (matchesRemote) { return remote; @@ -139,6 +140,7 @@ public class AccountRecordProcessor extends DefaultStorageRecordProcessor defaultReactions, - @NonNull SignalAccountRecord.Subscriber subscriber) + @NonNull SignalAccountRecord.Subscriber subscriber, + boolean displayBadgesOnProfile) { return Arrays.equals(contact.serializeUnknownFields(), unknownFields) && Objects.equals(contact.getGivenName().or(""), givenName) && @@ -201,6 +204,7 @@ public class AccountRecordProcessor extends DefaultStorageRecordProcessor