From 14cd7bd0510c41d9969d6d2661b07449dad4a261 Mon Sep 17 00:00:00 2001 From: Max Radermacher Date: Wed, 27 Jul 2022 14:04:42 -0700 Subject: [PATCH] Handle already-redeemed gift badges --- Signal.xcodeproj/project.pbxproj | 8 ++ .../BadgeGiftingAlreadyRedeemedSheet.swift | 82 +++++++++++++++++++ .../Donations/BadgeThanksSheet.swift | 6 +- .../Cells/GiftBadgeView.swift | 5 +- ...onversationViewController+GiftBadges.swift | 7 ++ Signal/src/util/BadgeGiftingStrings.swift | 24 ++++++ .../translations/en.lproj/Localizable.strings | 2 +- 7 files changed, 124 insertions(+), 10 deletions(-) create mode 100644 Signal/src/ViewControllers/AppSettings/Donations/BadgeGiftingAlreadyRedeemedSheet.swift create mode 100644 Signal/src/util/BadgeGiftingStrings.swift diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 68cde9b3e2..4a74eaecae 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -766,6 +766,8 @@ 4CFF115323A9C2130007F9D7 /* UnreadIndicatorInteraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF115223A9C2130007F9D7 /* UnreadIndicatorInteraction.swift */; }; 500FE490288615BA00FA090C /* CachedBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 500FE48E2886148800FA090C /* CachedBadge.swift */; }; 500FE4E0288A11B000FA090C /* ConversationViewController+GiftBadges.swift in Sources */ = {isa = PBXBuildFile; fileRef = 500FE4DF288A11AF00FA090C /* ConversationViewController+GiftBadges.swift */; }; + 500FE4E2288A373100FA090C /* BadgeGiftingAlreadyRedeemedSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 500FE4E1288A373100FA090C /* BadgeGiftingAlreadyRedeemedSheet.swift */; }; + 500FE5042890510800FA090C /* BadgeGiftingStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 500FE5032890510800FA090C /* BadgeGiftingStrings.swift */; }; 503614CF282AF657008128B4 /* GiftBadgeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 503614CE282AF657008128B4 /* GiftBadgeView.swift */; }; 5042EAA3287F96FB00C9B19F /* VisibleBadgeResolverTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5042EAA2287F96FB00C9B19F /* VisibleBadgeResolverTest.swift */; }; 50CF28F02829C94800752AB3 /* CVComponentGiftBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50CF28EF2829C94800752AB3 /* CVComponentGiftBadge.swift */; }; @@ -2115,6 +2117,8 @@ 500FE46B2880914900FA090C /* my */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = my; path = translations/my.lproj/InfoPlist.strings; sourceTree = ""; }; 500FE48E2886148800FA090C /* CachedBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CachedBadge.swift; sourceTree = ""; }; 500FE4DF288A11AF00FA090C /* ConversationViewController+GiftBadges.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConversationViewController+GiftBadges.swift"; sourceTree = ""; }; + 500FE4E1288A373100FA090C /* BadgeGiftingAlreadyRedeemedSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeGiftingAlreadyRedeemedSheet.swift; sourceTree = ""; }; + 500FE5032890510800FA090C /* BadgeGiftingStrings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeGiftingStrings.swift; sourceTree = ""; }; 503614CE282AF657008128B4 /* GiftBadgeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GiftBadgeView.swift; sourceTree = ""; }; 503614D0282C5703008128B4 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ro; path = translations/ro.lproj/PluralAware.stringsdict; sourceTree = ""; }; 503614D1282C5728008128B4 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = fi; path = translations/fi.lproj/PluralAware.stringsdict; sourceTree = ""; }; @@ -4124,6 +4128,7 @@ isa = PBXGroup; children = ( 4CC1ECFA211A553000CC13BE /* AppUpdateNag.swift */, + 500FE5032890510800FA090C /* BadgeGiftingStrings.swift */, 34F1071F26D005340053EF4D /* BatchUpdate.swift */, 4C751BE423FA0284002A8AF1 /* ContactSupportAlert.swift */, 3498AC882513896400B1F315 /* Dependencies+MainApp.swift */, @@ -4999,6 +5004,7 @@ F9066F0627ECE41B008C9530 /* DonationReceiptsViewController.swift */, 888017912741F33B00346E9A /* BoostViewController.swift */, 8880179327430DDB00346E9A /* BadgeThanksSheet.swift */, + 500FE4E1288A373100FA090C /* BadgeGiftingAlreadyRedeemedSheet.swift */, F95427E5286E042200314EDA /* BadgeGiftThanksSheet.swift */, 881BB2892743531D00B609B8 /* BadgeDetailsSheet.swift */, F02564D7274EDF4600D7B48A /* BadgeExpirationSheet.swift */, @@ -6483,6 +6489,7 @@ 347C3829252CE69400F3D941 /* CVComponentState+GroupLink.swift in Sources */, 3498AC922518E92B00B1F315 /* PaymentsSettingsViewController.swift in Sources */, 3497972025DAA86100E99FA4 /* SendPaymentCompletionActionSheet.swift in Sources */, + 500FE5042890510800FA090C /* BadgeGiftingStrings.swift in Sources */, 343A65981FC4CFE7000477A1 /* ConversationScrollButton.m in Sources */, 34386A51207D0C01009F5D9C /* ChatListViewController.m in Sources */, 348EE28E25B897BF00814FC2 /* CVMediaCache.swift in Sources */, @@ -6521,6 +6528,7 @@ 887CD4772472FEA500FDD265 /* DeviceTransferOperation.swift in Sources */, 88D23D2023CEC0C700B0E74B /* IndividualCallService.swift in Sources */, 88863A52280CAE6A00977F69 /* StoryInteractiveTransitionCoordinator.swift in Sources */, + 500FE4E2288A373100FA090C /* BadgeGiftingAlreadyRedeemedSheet.swift in Sources */, 8845B0C9264F12F800FA694C /* GroupDescriptionPreviewView.swift in Sources */, 500FE4E0288A11B000FA090C /* ConversationViewController+GiftBadges.swift in Sources */, 4CD675BE22E7BE35008010D2 /* MediaDismissAnimationController.swift in Sources */, diff --git a/Signal/src/ViewControllers/AppSettings/Donations/BadgeGiftingAlreadyRedeemedSheet.swift b/Signal/src/ViewControllers/AppSettings/Donations/BadgeGiftingAlreadyRedeemedSheet.swift new file mode 100644 index 0000000000..998c518551 --- /dev/null +++ b/Signal/src/ViewControllers/AppSettings/Donations/BadgeGiftingAlreadyRedeemedSheet.swift @@ -0,0 +1,82 @@ +// +// Copyright (c) 2022 Open Whisper Systems. All rights reserved. +// + +import Foundation +import SignalUI +import UIKit + +class BadgeGiftingAlreadyRedeemedSheet: OWSTableSheetViewController { + private let profileBadge: ProfileBadge + private let fullName: String + + public init(badge: ProfileBadge, fullName: String) { + owsAssertDebug(badge.assets != nil) + + self.profileBadge = badge + self.fullName = fullName + + super.init() + + updateTableContents() + } + + public required init() { + fatalError("init() has not been implemented") + } + + public override func updateTableContents(shouldReload: Bool = true) { + let contents = OWSTableContents() + defer { tableViewController.setContents(contents, shouldReload: shouldReload) } + + let headerSection = OWSTableSection() + headerSection.hasBackground = false + headerSection.customHeaderHeight = 1 + contents.addSection(headerSection) + + headerSection.add(.init(customCellBlock: { [weak self] in + let cell = OWSTableItem.newCell() + guard let self = self else { return cell } + cell.selectionStyle = .none + + let stackView = UIStackView() + stackView.axis = .vertical + stackView.alignment = .center + stackView.layoutMargins = UIEdgeInsets(hMargin: 24, vMargin: 0) + stackView.isLayoutMarginsRelativeArrangement = true + + cell.contentView.addSubview(stackView) + stackView.autoPinEdgesToSuperviewEdges() + + let badgeImageView = UIImageView() + badgeImageView.image = self.profileBadge.assets?.universal160 + badgeImageView.autoSetDimensions(to: CGSize(square: 160)) + stackView.addArrangedSubview(badgeImageView) + stackView.setCustomSpacing(24, after: badgeImageView) + + let titleLabel = UILabel() + titleLabel.font = .ows_dynamicTypeTitle2.ows_semibold + titleLabel.textColor = Theme.primaryTextColor + titleLabel.textAlignment = .center + titleLabel.numberOfLines = 0 + titleLabel.text = BadgeGiftingStrings.giftBadgeTitle + stackView.addArrangedSubview(titleLabel) + stackView.setCustomSpacing(12, after: titleLabel) + + let label = UILabel() + label.font = .ows_dynamicTypeBody + label.textColor = Theme.primaryTextColor + label.numberOfLines = 0 + label.text = BadgeGiftingStrings.youReceived(from: self.fullName) + label.textAlignment = .center + stackView.addArrangedSubview(label) + + return cell + }, actionBlock: nil)) + } + + public override func willDismissInteractively() { + super.willDismissInteractively() + self.dismiss(animated: true) + } +} diff --git a/Signal/src/ViewControllers/AppSettings/Donations/BadgeThanksSheet.swift b/Signal/src/ViewControllers/AppSettings/Donations/BadgeThanksSheet.swift index 3fd6f0f480..57dde22c5f 100644 --- a/Signal/src/ViewControllers/AppSettings/Donations/BadgeThanksSheet.swift +++ b/Signal/src/ViewControllers/AppSettings/Donations/BadgeThanksSheet.swift @@ -267,11 +267,7 @@ class BadgeThanksSheet: OWSTableSheetViewController { ) return String(format: formatText, self.badge.localizedName) case .gift(_, fullName: let fullName, _, _): - let formatText = NSLocalizedString( - "BADGE_GIFTING_YOU_RECEIVED_FORMAT", - comment: "Shown when redeeming a gift you received to explain to the user that they've earned a badge. Embed {contact name}." - ) - return String(format: formatText, fullName) + return BadgeGiftingStrings.youReceived(from: fullName) } } diff --git a/Signal/src/ViewControllers/ConversationView/Cells/GiftBadgeView.swift b/Signal/src/ViewControllers/ConversationView/Cells/GiftBadgeView.swift index 76451fecd5..a14bcf2b03 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/GiftBadgeView.swift +++ b/Signal/src/ViewControllers/ConversationView/Cells/GiftBadgeView.swift @@ -61,10 +61,7 @@ class GiftBadgeView: ManualStackView { private static func titleLabelConfig(for state: State) -> CVLabelConfig { let textColor = state.conversationStyle.bubbleTextColor(isIncoming: state.isIncoming) return CVLabelConfig( - text: NSLocalizedString( - "BADGE_GIFTING_CHAT_TITLE", - comment: "Shown on a gift badge message to indicate that the message contains a gift." - ), + text: BadgeGiftingStrings.giftBadgeTitle, font: .ows_dynamicTypeBody, textColor: textColor, numberOfLines: 0 diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController+GiftBadges.swift b/Signal/src/ViewControllers/ConversationView/ConversationViewController+GiftBadges.swift index 0ff73eb67f..a62aa8ad06 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController+GiftBadges.swift +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController+GiftBadges.swift @@ -96,6 +96,13 @@ extension ConversationViewController { sheet.delegate = self return sheet } + if isRedeemed { + let fullName = self.databaseStorage.read { transaction -> String in + let authorAddress = incomingMessage.authorAddress + return self.contactsManager.displayName(for: authorAddress, transaction: transaction) + } + return BadgeGiftingAlreadyRedeemedSheet(badge: profileBadge, fullName: fullName) + } return self.giftRedemptionSheet(incomingMessage: incomingMessage, profileBadge: profileBadge) } diff --git a/Signal/src/util/BadgeGiftingStrings.swift b/Signal/src/util/BadgeGiftingStrings.swift new file mode 100644 index 0000000000..3d81e94c4c --- /dev/null +++ b/Signal/src/util/BadgeGiftingStrings.swift @@ -0,0 +1,24 @@ +// +// Copyright (c) 2022 Open Whisper Systems. All rights reserved. +// + +import Foundation + +struct BadgeGiftingStrings { + private init() {} + + static var giftBadgeTitle: String { + NSLocalizedString( + "BADGE_GIFTING_CHAT_TITLE", + comment: "Shown on a gift badge message and when tapping a redeemed gift message to denote the presence of a gift badge." + ) + } + + static func youReceived(from fullName: String) -> String { + let formatText = NSLocalizedString( + "BADGE_GIFTING_YOU_RECEIVED_FORMAT", + comment: "Shown when redeeming a gift you received to explain to the user that they've earned a badge. Embed {contact name}." + ) + return String(format: formatText, fullName) + } +} diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 7d336c6c03..f707d732f1 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -421,7 +421,7 @@ /* Shown on a gift badge message to indicate that it's already expired and can no longer be redeemed. */ "BADGE_GIFTING_CHAT_EXPIRED" = "Expired"; -/* Shown on a gift badge message to indicate that the message contains a gift. */ +/* Shown on a gift badge message and when tapping a redeemed gift message to denote the presence of a gift badge. */ "BADGE_GIFTING_CHAT_TITLE" = "Gift Badge"; /* Short paragraph on the screen where you choose a gift badge */