From ef6c044a546ff561b6c5febfe4927f9bc263b426 Mon Sep 17 00:00:00 2001 From: Evan Hahn Date: Fri, 15 Apr 2022 12:29:47 -0500 Subject: [PATCH] Remove legacy donation view _I recommend reviewing this with whitespace changes disabled._ We have a kill switch that disables badge acquisition. If that kill switch is active, we show a one-time donation view. That kill switch has been off since January of 2021, so I think we can remove this one-time donation view. That lets us remove hundreds of lines of code, but it will also make future donation-related changes a bit easier. --- Signal.xcodeproj/project.pbxproj | 4 - .../character-loving.imageset/Contents.json | 12 - .../donate_light_dark2.pdf | Bin 31098 -> 0 bytes .../AppSettingsViewController.swift | 87 +- .../AppSettings/DonationViewController.swift | 763 ------------------ .../ConversationSearchViewController.swift | 4 + .../translations/en.lproj/Localizable.strings | 30 - SignalServiceKit/src/Util/FeatureFlags.swift | 3 - .../src/Util/RemoteConfigManager.swift | 9 +- 9 files changed, 43 insertions(+), 869 deletions(-) delete mode 100644 Signal/Images.xcassets/character-loving.imageset/Contents.json delete mode 100644 Signal/Images.xcassets/character-loving.imageset/donate_light_dark2.pdf delete mode 100644 Signal/src/ViewControllers/AppSettings/DonationViewController.swift diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index e61f86e487..0fefeaeb49 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -977,7 +977,6 @@ 88F58A1725EEE5B9008CDA24 /* AppSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F58A1625EEE5B9008CDA24 /* AppSettingsViewController.swift */; }; 88F67A0C24E5126D00435A71 /* HapticFeedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C090A1A210FD9C7001FD7F9 /* HapticFeedback.swift */; }; 88F7EE93230253C5003ADF7D /* UsernameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F7EE92230253C5003ADF7D /* UsernameViewController.swift */; }; - 88FBE9502649E7EB005F6C80 /* DonationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FBE94F2649E7EB005F6C80 /* DonationViewController.swift */; }; 88FBE954264B6849005F6C80 /* SubscriptionMegaphone.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FBE953264B6848005F6C80 /* SubscriptionMegaphone.swift */; }; 88FE237E249C22080041670F /* ConversationViewController+Scroll.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FE237D249C22080041670F /* ConversationViewController+Scroll.swift */; }; 954AEE6A1DF33E01002E5410 /* ContactsPickerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 954AEE681DF33D32002E5410 /* ContactsPickerTest.swift */; }; @@ -2292,7 +2291,6 @@ 88EFF4FB25AD4230000FAFBA /* SharingThreadPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharingThreadPickerViewController.swift; sourceTree = ""; }; 88F58A1625EEE5B9008CDA24 /* AppSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettingsViewController.swift; sourceTree = ""; }; 88F7EE92230253C5003ADF7D /* UsernameViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsernameViewController.swift; sourceTree = ""; }; - 88FBE94F2649E7EB005F6C80 /* DonationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DonationViewController.swift; sourceTree = ""; }; 88FBE953264B6848005F6C80 /* SubscriptionMegaphone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionMegaphone.swift; sourceTree = ""; }; 88FE237D249C22080041670F /* ConversationViewController+Scroll.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConversationViewController+Scroll.swift"; sourceTree = ""; }; 8981C8F64D94D3C52EB67A2C /* Pods-SignalTests.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalTests.test.xcconfig"; path = "Pods/Target Support Files/Pods-SignalTests/Pods-SignalTests.test.xcconfig"; sourceTree = ""; }; @@ -2655,7 +2653,6 @@ 887B380725F0355700685845 /* ChatsSettingsViewController.swift */, 3414896825C9B6490098E3ED /* CurrencyPickerViewController.swift */, 887B6DCC25F6C41500E677D4 /* Data Usage */, - 88FBE94F2649E7EB005F6C80 /* DonationViewController.swift */, F0CA67F92728A89A002B9DFE /* SubscriptionViewController.swift */, 32ECD08624BFBF5C00EDDED0 /* Help */, 887B6DCE25F6C45B00E677D4 /* Internal */, @@ -6359,7 +6356,6 @@ 458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */, 3491899B269CD68E008A18AF /* BlockingAnnouncementOnlyView.swift in Sources */, 88D23D2323CEC0C700B0E74B /* NonCallKitCallUIAdaptee.swift in Sources */, - 88FBE9502649E7EB005F6C80 /* DonationViewController.swift in Sources */, 34B6A905218B4C91007C4606 /* TypingIndicatorInteraction.swift in Sources */, 884DB95027DE67BB00C6A309 /* StoryContextViewController.swift in Sources */, 34A4D87F2677B23100A794E7 /* ConversationViewController+MessageActions.swift in Sources */, diff --git a/Signal/Images.xcassets/character-loving.imageset/Contents.json b/Signal/Images.xcassets/character-loving.imageset/Contents.json deleted file mode 100644 index 85dec059d7..0000000000 --- a/Signal/Images.xcassets/character-loving.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "filename" : "donate_light_dark2.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Signal/Images.xcassets/character-loving.imageset/donate_light_dark2.pdf b/Signal/Images.xcassets/character-loving.imageset/donate_light_dark2.pdf deleted file mode 100644 index 47f106ad1f46a9e6783d89f531811651559f7014..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31098 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 UITableViewCell { - let cell = OWSTableItem.newCell() - cell.selectionStyle = .none - cell.layoutMargins = cellOuterInsets - cell.contentView.layoutMargins = .zero - return cell - } - - override var canBecomeFirstResponder: Bool { true } - override func becomeFirstResponder() -> Bool { - let result = super.becomeFirstResponder() - // If we become the first responder, but the user was entering - // a customValue, restore the first responder state to the text field. - if result, case .customValueSelected = state { - customValueTextField.becomeFirstResponder() - } - return result - } - - var presetButtons: [UInt: UIView] = [:] - func updatePresetButtonSelection() { - for (amount, button) in presetButtons { - if case .presetSelected(amount: amount) = self.state { - button.layer.borderColor = Theme.accentBlueColor.cgColor - } else { - button.layer.borderColor = Self.bubbleBorderColor.cgColor - } - } - } - - func updateTableContents() { - let contents = OWSTableContents() - defer { - self.contents = contents - if case .customValueSelected = state { customValueTextField.becomeFirstResponder() } - } - - let section = OWSTableSection() - section.hasBackground = false - contents.addSection(section) - - section.customHeaderView = { - let stackView = UIStackView() - stackView.axis = .vertical - stackView.alignment = .center - stackView.isLayoutMarginsRelativeArrangement = true - stackView.layoutMargins = UIEdgeInsets(top: 0, left: 16, bottom: 28, right: 16) - - let imageView = UIImageView() - imageView.image = #imageLiteral(resourceName: "character-loving") - imageView.contentMode = .scaleAspectFit - imageView.autoSetDimension(.height, toSize: 144) - stackView.addArrangedSubview(imageView) - - let label = UILabel() - label.textAlignment = .center - label.font = UIFont.ows_dynamicTypeTitle2.ows_semibold - label.text = NSLocalizedString( - "DONATION_VIEW_TITLE", - comment: "Title for the donate to signal view" - ) - label.numberOfLines = 0 - label.lineBreakMode = .byWordWrapping - stackView.addArrangedSubview(label) - - return stackView - }() - - if case .donatedSuccessfully = state { - section.add(.init( - customCellBlock: { [weak self] in - guard let self = self else { return UITableViewCell() } - let cell = self.newCell() - - let backgroundView = UIView() - backgroundView.backgroundColor = Self.bubbleBackgroundColor - backgroundView.layer.cornerRadius = 12 - cell.insertSubview(backgroundView, belowSubview: cell.contentView) - backgroundView.autoPinEdgesToSuperviewMargins() - - cell.contentView.layoutMargins = UIEdgeInsets( - hMargin: Self.cellHInnerMargin, - vMargin: 38 - ) - - let label = UILabel() - label.textAlignment = .center - label.font = .ows_dynamicTypeBody - label.textColor = Theme.primaryTextColor - label.text = NSLocalizedString( - "DONATION_VIEW_THANKS_FOR_YOUR_SUPPORT", - comment: "Thank you message on the donate to signal view" - ) - label.numberOfLines = 0 - label.lineBreakMode = .byWordWrapping - - cell.contentView.addSubview(label) - label.autoPinEdgesToSuperviewMargins() - - return cell - }, - actionBlock: {} - )) - } else { - addApplePayItemsIfAvailable(to: section) - - // If ApplePay isn't available, show just a link to the website - if !DonationUtilities.isApplePayAvailable { - section.add(.init( - customCellBlock: { [weak self] in - guard let self = self else { return UITableViewCell() } - let cell = self.newCell() - - let donateButton = OWSFlatButton() - donateButton.setBackgroundColors(upColor: Theme.accentBlueColor) - donateButton.setTitleColor(.ows_white) - donateButton.setAttributedTitle(NSAttributedString.composed(of: [ - NSLocalizedString( - "SETTINGS_DONATE", - comment: "Title for the 'donate to signal' link in settings." - ), - Special.noBreakSpace, - NSAttributedString.with( - image: #imageLiteral(resourceName: "open-20").withRenderingMode(.alwaysTemplate), - font: UIFont.ows_dynamicTypeBodyClamped.ows_semibold - ) - ]).styled( - with: .font(UIFont.ows_dynamicTypeBodyClamped.ows_semibold), - .color(.ows_white) - )) - donateButton.layer.cornerRadius = 12 - donateButton.clipsToBounds = true - donateButton.setPressedBlock { [weak self] in - self?.openDonateWebsite() - } - - cell.contentView.addSubview(donateButton) - donateButton.autoPinEdgesToSuperviewMargins() - donateButton.autoSetDimension(.height, toSize: 48, relation: .greaterThanOrEqual) - - return cell - }, - actionBlock: {} - )) - } - } - - let whySection = OWSTableSection() - whySection.hasBackground = false - contents.addSection(whySection) - - whySection.add(.init( - customCellBlock: { [weak self] in - guard let self = self else { return UITableViewCell() } - let cell = self.newCell() - - let label = UILabel() - label.font = UIFont.ows_dynamicTypeTitle2.ows_semibold - label.textColor = Theme.primaryTextColor - label.text = NSLocalizedString( - "DONATION_VIEW_WHY_DONATE_TITLE", - comment: "The title of the 'Why Donate' section of the donate to signal view" - ) - label.numberOfLines = 0 - label.lineBreakMode = .byWordWrapping - - cell.contentView.addSubview(label) - label.autoPinEdgesToSuperviewMargins() - - return cell - }, - actionBlock: {} - )) - - whySection.add(.init( - customCellBlock: { [weak self] in - guard let self = self else { return UITableViewCell() } - let cell = self.newCell() - - let label = UILabel() - label.font = .ows_dynamicTypeBody - label.textColor = Theme.primaryTextColor - label.text = NSLocalizedString( - "DONATION_VIEW_WHY_DONATE_BODY", - comment: "The body of the 'Why Donate' section of the donate to signal view" - ) - label.numberOfLines = 0 - label.lineBreakMode = .byWordWrapping - - cell.contentView.addSubview(label) - label.autoPinEdgesToSuperviewMargins() - - return cell - }, - actionBlock: {} - )) - } - - private func openDonateWebsite() { - UIApplication.shared.open(URL(string: "https://signal.org/donate")!, options: [:], completionHandler: nil) - } -} - -// MARK: - ApplePay - -extension DonationViewController: PKPaymentAuthorizationControllerDelegate { - - func addApplePayItemsIfAvailable(to section: OWSTableSection) { - guard DonationUtilities.isApplePayAvailable else { return } - - // Currency Picker - - section.add(.init( - customCellBlock: { [weak self] in - guard let self = self else { return UITableViewCell() } - let cell = self.newCell() - - let stackView = UIStackView() - stackView.axis = .horizontal - stackView.alignment = .center - stackView.spacing = 8 - cell.contentView.addSubview(stackView) - stackView.autoPinEdgesToSuperviewEdges() - - let label = UILabel() - label.font = .ows_dynamicTypeBodyClamped - label.textColor = Theme.primaryTextColor - label.text = NSLocalizedString( - "DONATION_VIEW_AMOUNT_LABEL", - comment: "Donation amount label for the donate to signal view" - ) - stackView.addArrangedSubview(label) - - let picker = OWSButton { [weak self] in - guard let self = self else { return } - let vc = CurrencyPickerViewController( - dataSource: StripeCurrencyPickerDataSource(currentCurrencyCode: self.currencyCode) - ) { [weak self] currencyCode in - self?.currencyCode = currencyCode - } - self.navigationController?.pushViewController(vc, animated: true) - } - - picker.setAttributedTitle(NSAttributedString.composed(of: [ - self.currencyCode, - Special.noBreakSpace, - NSAttributedString.with( - image: #imageLiteral(resourceName: "chevron-down-18").withRenderingMode(.alwaysTemplate), - font: .ows_regularFont(withSize: 17) - ).styled( - with: .color(Self.bubbleBorderColor) - ) - ]).styled( - with: .font(.ows_regularFont(withSize: 17)), - .color(Theme.primaryTextColor) - ), for: .normal) - - picker.setBackgroundImage(UIImage.init(color: Self.bubbleBackgroundColor), for: .normal) - picker.setBackgroundImage(UIImage.init(color: Self.bubbleBackgroundColor.withAlphaComponent(0.8)), for: .highlighted) - - let pillView = PillView() - pillView.layer.borderWidth = Self.bubbleBorderWidth - pillView.layer.borderColor = Self.bubbleBorderColor.cgColor - pillView.clipsToBounds = true - pillView.addSubview(picker) - picker.autoPinEdgesToSuperviewEdges() - picker.autoSetDimension(.width, toSize: 74, relation: .greaterThanOrEqual) - - stackView.addArrangedSubview(pillView) - pillView.autoSetDimension(.height, toSize: 36, relation: .greaterThanOrEqual) - - let leadingSpacer = UIView.hStretchingSpacer() - let trailingSpacer = UIView.hStretchingSpacer() - stackView.insertArrangedSubview(leadingSpacer, at: 0) - stackView.addArrangedSubview(trailingSpacer) - leadingSpacer.autoMatch(.width, to: .width, of: trailingSpacer) - - return cell - }, - actionBlock: {} - )) - - // Preset donation options - - if let preset = DonationUtilities.Presets.presets[currencyCode] { - section.add(.init( - customCellBlock: { [weak self] in - guard let self = self else { return UITableViewCell() } - let cell = self.newCell() - - let vStack = UIStackView() - vStack.axis = .vertical - vStack.distribution = .fillEqually - vStack.spacing = 16 - cell.contentView.addSubview(vStack) - vStack.autoPinEdgesToSuperviewMargins() - - self.presetButtons.removeAll() - - for amounts in preset.amounts.chunked(by: 3) { - let hStack = UIStackView() - hStack.axis = .horizontal - hStack.distribution = .fillEqually - hStack.spacing = UIDevice.current.isIPhone5OrShorter ? 8 : 14 - - vStack.addArrangedSubview(hStack) - - for amount in amounts { - let button = OWSFlatButton() - hStack.addArrangedSubview(button) - button.setBackgroundColors( - upColor: Self.bubbleBackgroundColor, - downColor: Self.bubbleBackgroundColor.withAlphaComponent(0.8) - ) - button.layer.cornerRadius = 12 - button.clipsToBounds = true - button.layer.borderWidth = Self.bubbleBorderWidth - button.setPressedBlock { [weak self] in - self?.state = .presetSelected(amount: amount) - } - - button.setTitle( - title: DonationUtilities.formatCurrency(NSDecimalNumber(value: amount), currencyCode: self.currencyCode), - font: .ows_regularFont(withSize: UIDevice.current.isIPhone5OrShorter ? 18 : 20), - titleColor: Theme.primaryTextColor - ) - - button.autoSetDimension(.height, toSize: 48) - - self.presetButtons[amount] = button - } - } - - self.updatePresetButtonSelection() - - return cell - }, - actionBlock: {} - )) - } - - // Custom donation option - - let applePayButtonIndex = IndexPath(row: section.items.count + 1, section: 0) - let customValueTextField = self.customValueTextField - section.add(.init( - customCellBlock: { [weak self] in - guard let self = self else { return UITableViewCell() } - let cell = self.newCell() - - customValueTextField.backgroundColor = Self.bubbleBackgroundColor - customValueTextField.layer.cornerRadius = 12 - customValueTextField.layer.borderWidth = Self.bubbleBorderWidth - customValueTextField.layer.borderColor = Self.bubbleBorderColor.cgColor - - customValueTextField.font = .ows_dynamicTypeBodyClamped - customValueTextField.textColor = Theme.primaryTextColor - - cell.contentView.addSubview(customValueTextField) - customValueTextField.autoPinEdgesToSuperviewMargins() - - return cell - }, - actionBlock: { [weak self] in - customValueTextField.becomeFirstResponder() - self?.tableView.scrollToRow(at: applePayButtonIndex, at: .bottom, animated: true) - } - )) - - // Donate with Apple Pay button - - section.add(.init( - customCellBlock: { [weak self] in - guard let self = self else { return UITableViewCell() } - let cell = self.newCell() - - let donateButton = PKPaymentButton( - paymentButtonType: .donate, - paymentButtonStyle: Theme.isDarkThemeEnabled ? .white : .black - ) - donateButton.cornerRadius = 12 - donateButton.addTarget(self, action: #selector(self.requestApplePayDonation), for: .touchUpInside) - cell.contentView.addSubview(donateButton) - donateButton.autoPinEdgesToSuperviewMargins() - donateButton.autoSetDimension(.height, toSize: 48, relation: .greaterThanOrEqual) - - return cell - }, - actionBlock: {} - )) - - // Other options button - - section.add(.init( - customCellBlock: { [weak self] in - guard let self = self else { return UITableViewCell() } - let cell = self.newCell() - - let donateButton = OWSFlatButton() - donateButton.setTitleColor(Theme.accentBlueColor) - donateButton.setAttributedTitle(NSAttributedString.composed(of: [ - NSLocalizedString( - "DONATION_VIEW_OTHER_WAYS", - comment: "Text explaining there are other ways to donate on the donation view." - ), - Special.noBreakSpace, - NSAttributedString.with( - image: #imageLiteral(resourceName: "open-20").withRenderingMode(.alwaysTemplate), - font: .ows_dynamicTypeBodyClamped - ) - ]).styled( - with: .font(.ows_dynamicTypeBodyClamped), - .color(Theme.accentBlueColor) - )) - donateButton.setPressedBlock { [weak self] in - self?.openDonateWebsite() - } - - cell.contentView.addSubview(donateButton) - donateButton.autoPinEdgesToSuperviewMargins() - - return cell - }, - actionBlock: {} - )) - } - - @objc - func requestApplePayDonation() { - guard let donationAmount = donationAmount else { - presentToast(text: NSLocalizedString( - "DONATION_VIEW_SELECT_AN_AMOUNT", - comment: "Error text notifying the user they must select an amount on the donate to signal view" - ), extraVInset: view.height - tableView.frame.maxY) - return - } - - guard !Stripe.isAmountTooSmall(donationAmount, in: currencyCode) else { - presentToast(text: NSLocalizedString( - "DONATION_VIEW_SELECT_A_LARGER_AMOUNT", - comment: "Error text notifying the user they must select a large amount on the donate to signal view" - ), extraVInset: view.height - tableView.frame.maxY) - return - } - - guard !Stripe.isAmountTooLarge(donationAmount, in: currencyCode) else { - presentToast(text: NSLocalizedString( - "DONATION_VIEW_SELECT_A_SMALLER_AMOUNT", - comment: "Error text notifying the user they must select a smaller amount on the donate to signal view" - ), extraVInset: view.height - tableView.frame.maxY) - return - } - - let request = DonationUtilities.newPaymentRequest(for: donationAmount, currencyCode: currencyCode) - - let paymentController = PKPaymentAuthorizationController(paymentRequest: request) - paymentController.delegate = self - paymentController.present { presented in - if !presented { owsFailDebug("Failed to present payment controller") } - } - } - - func paymentAuthorizationControllerDidFinish(_ controller: PKPaymentAuthorizationController) { - controller.dismiss() - } - - func paymentAuthorizationController( - _ controller: PKPaymentAuthorizationController, - didAuthorizePayment payment: PKPayment, - handler completion: @escaping (PKPaymentAuthorizationResult) -> Void - ) { - guard let donationAmount = donationAmount else { - completion(.init(status: .failure, errors: [OWSAssertionError("Missing donation amount")])) - return - } - Stripe.donate(amount: donationAmount, in: currencyCode, for: payment).done { [weak self] in - completion(.init(status: .success, errors: nil)) - self?.state = .donatedSuccessfully - }.catch { error in - owsFailDebugUnlessNetworkFailure(error) - completion(.init(status: .failure, errors: [error])) - } - } -} - -// MARK: - CustomValueTextField - -private protocol CustomValueTextFieldDelegate: AnyObject { - func customValueTextFieldStateDidChange(_ textField: CustomValueTextField) -} - -private class CustomValueTextField: UIView { - private let placeholderLabel = UILabel() - private let symbolLabel = UILabel() - private let textField = UITextField() - private let stackView = UIStackView() - - weak var delegate: CustomValueTextFieldDelegate? - - @discardableResult - override func becomeFirstResponder() -> Bool { textField.becomeFirstResponder() } - - @discardableResult - override func resignFirstResponder() -> Bool { textField.resignFirstResponder() } - - override var canBecomeFirstResponder: Bool { textField.canBecomeFirstResponder } - override var canResignFirstResponder: Bool { textField.canResignFirstResponder } - override var isFirstResponder: Bool { textField.isFirstResponder } - - init() { - super.init(frame: .zero) - textField.autocorrectionType = .no - textField.spellCheckingType = .no - textField.keyboardType = .decimalPad - textField.textAlignment = .center - textField.delegate = self - - symbolLabel.textAlignment = .center - placeholderLabel.textAlignment = .center - - stackView.axis = .horizontal - - stackView.addArrangedSubview(placeholderLabel) - stackView.addArrangedSubview(textField) - - addSubview(stackView) - stackView.autoPinHeightToSuperview() - stackView.autoMatch(.width, to: .width, of: self, withMultiplier: 1, relation: .lessThanOrEqual) - stackView.autoHCenterInSuperview() - stackView.autoSetDimension(.height, toSize: 48, relation: .greaterThanOrEqual) - - updateVisibility() - setCurrencyCode(currencyCode) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - var text: String? { - set { - textField.text = newValue - updateVisibility() - } - get { textField.text } - } - - var decimalNumber: NSDecimalNumber? { - let number = NSDecimalNumber(string: valueString(for: text), locale: Locale.current) - guard number != NSDecimalNumber.notANumber else { return nil } - return number - } - - var font: UIFont? { - set { - textField.font = newValue - placeholderLabel.font = newValue - symbolLabel.font = newValue - } - get { textField.font } - } - - var textColor: UIColor? { - set { - textField.textColor = newValue - placeholderLabel.textColor = newValue - symbolLabel.textColor = newValue - } - get { textField.textColor } - } - - var placeholder: String? { - set { placeholderLabel.text = newValue } - get { placeholderLabel.text } - } - - private lazy var symbol: DonationUtilities.Symbol = DonationUtilities.Presets.presets[currencyCode]?.symbol ?? .currencyCode - private lazy var currencyCode = Stripe.defaultCurrencyCode - - func setCurrencyCode(_ currencyCode: Currency.Code) { - self.symbol = DonationUtilities.Presets.symbol(for: currencyCode) - self.currencyCode = currencyCode - - symbolLabel.removeFromSuperview() - - switch symbol { - case .before(let symbol): - symbolLabel.text = symbol - stackView.insertArrangedSubview(symbolLabel, at: 0) - case .after(let symbol): - symbolLabel.text = symbol - stackView.addArrangedSubview(symbolLabel) - case .currencyCode: - symbolLabel.text = currencyCode + " " - stackView.insertArrangedSubview(symbolLabel, at: 0) - } - } - - func updateVisibility() { - let shouldShowPlaceholder = text.isEmptyOrNil && !isFirstResponder - placeholderLabel.isHiddenInStackView = !shouldShowPlaceholder - symbolLabel.isHiddenInStackView = shouldShowPlaceholder - textField.isHiddenInStackView = shouldShowPlaceholder - } -} - -extension CustomValueTextField: UITextFieldDelegate { - func textFieldDidBeginEditing(_ textField: UITextField) { - updateVisibility() - delegate?.customValueTextFieldStateDidChange(self) - } - - func textFieldDidEndEditing(_ textField: UITextField) { - updateVisibility() - } - - func textField(_ textField: UITextField, shouldChangeCharactersIn editingRange: NSRange, replacementString: String) -> Bool { - let existingString = textField.text ?? "" - - let newString = (existingString as NSString).replacingCharacters(in: editingRange, with: replacementString) - if let numberString = self.valueString(for: newString) { - textField.text = numberString - // Make a best effort to preserve cursor position - if let newPosition = textField.position( - from: textField.beginningOfDocument, - offset: editingRange.location + max(0, numberString.count - existingString.count) - ) { - textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition) - } - } else { - textField.text = "" - } - - updateVisibility() - delegate?.customValueTextFieldStateDidChange(self) - - return false - } - - /// Converts an arbitrary string into a string representing a valid value - /// for the current currency. If no valid value is represented, returns nil - func valueString(for string: String?) -> String? { - guard let string = string else { return nil } - - let isZeroDecimalCurrency = Stripe.zeroDecimalCurrencyCodes.contains(currencyCode) - guard !isZeroDecimalCurrency else { return string.digitsOnly } - - let decimalSeparator = Locale.current.decimalSeparator ?? "." - let components = string.components(separatedBy: decimalSeparator).compactMap { $0.digitsOnly.nilIfEmpty } - - guard let integralString = components.first else { - if string.contains(decimalSeparator) { - return "0" + decimalSeparator - } else { - return nil - } - } - - if let decimalString = components.dropFirst().joined().nilIfEmpty { - return integralString + decimalSeparator + decimalString - } else if string.starts(with: decimalSeparator) { - return "0" + decimalSeparator + integralString - } else if string.contains(decimalSeparator) { - return integralString + decimalSeparator - } else { - return integralString - } - } -} - -extension DonationViewController: CustomValueTextFieldDelegate { - fileprivate func customValueTextFieldStateDidChange(_ textField: CustomValueTextField) { - state = .customValueSelected - } -} diff --git a/Signal/src/ViewControllers/HomeView/Chat List/ConversationSearchViewController.swift b/Signal/src/ViewControllers/HomeView/Chat List/ConversationSearchViewController.swift index 1e267bf988..034d9d9887 100644 --- a/Signal/src/ViewControllers/HomeView/Chat List/ConversationSearchViewController.swift +++ b/Signal/src/ViewControllers/HomeView/Chat List/ConversationSearchViewController.swift @@ -5,6 +5,10 @@ import Foundation import BonMot +/* From BonMot 6.0.0: If you're targeting iOS 15 or higher, you may want to check out [AttributedString](https://developer.apple.com/documentation/foundation/attributedstring) instead. + If you're an existing user of BonMot using Xcode 13, you may want to add the following `typealias` somewhere in your project to avoid a conflict with `Foundation.StringStyle`: */ +typealias StringStyle = BonMot.StringStyle + @objc public protocol ConversationSearchViewDelegate: AnyObject { func conversationSearchViewWillBeginDragging() diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 746941b970..340e5f84a0 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -1639,39 +1639,9 @@ /* Text at the bottom of the donation receipts list, telling users that receipts might not be available */ "DONATION_RECEIPTS_MIGHT_BE_MISSING_IF_YOU_REINSTALLED" = "If you have reinstalled Signal, receipts from previous donations will not be available."; -/* Donation amount label for the donate to signal view */ -"DONATION_VIEW_AMOUNT_LABEL" = "Donation amount"; - -/* Default text for the custom amount field of the donation view. */ -"DONATION_VIEW_CUSTOM_AMOUNT_PLACEHOLDER" = "Enter Custom Amount"; - /* Text describing to the user that they're going to pay a donation to Signal */ "DONATION_VIEW_DONATION_TO_SIGNAL" = "Donation to Signal"; -/* Text explaining there are other ways to donate on the donation view. */ -"DONATION_VIEW_OTHER_WAYS" = "Other Ways to Donate"; - -/* Error text notifying the user they must select a large amount on the donate to signal view */ -"DONATION_VIEW_SELECT_A_LARGER_AMOUNT" = "Select a larger amount to donate"; - -/* Error text notifying the user they must select a smaller amount on the donate to signal view */ -"DONATION_VIEW_SELECT_A_SMALLER_AMOUNT" = "Select a smaller amount to donate"; - -/* Error text notifying the user they must select an amount on the donate to signal view */ -"DONATION_VIEW_SELECT_AN_AMOUNT" = "Select an amount to donate"; - -/* Thank you message on the donate to signal view */ -"DONATION_VIEW_THANKS_FOR_YOUR_SUPPORT" = "Thank you for your support!"; - -/* Title for the donate to signal view */ -"DONATION_VIEW_TITLE" = "Signal is powered by people like you."; - -/* The body of the 'Why Donate' section of the donate to signal view */ -"DONATION_VIEW_WHY_DONATE_BODY" = "The team at Signal is committed to the mission of developing open source privacy technology that protects free expression and enables secure global communication. Your contribution fuels this cause. No ads. No trackers. No kidding.\n\nYour donation helps pay for the development, servers, and bandwidth of an app used by millions around the world for private and instantaneous communication."; - -/* The title of the 'Why Donate' section of the donate to signal view */ -"DONATION_VIEW_WHY_DONATE_TITLE" = "Why Donate?"; - /* Alert body for when the user has just tried to edit a contacts after declining to give Signal contacts permissions */ "EDIT_CONTACT_WITHOUT_CONTACTS_PERMISSION_ALERT_BODY" = "You can enable access in the iOS Settings app."; diff --git a/SignalServiceKit/src/Util/FeatureFlags.swift b/SignalServiceKit/src/Util/FeatureFlags.swift index 04618af463..f03ab7307e 100644 --- a/SignalServiceKit/src/Util/FeatureFlags.swift +++ b/SignalServiceKit/src/Util/FeatureFlags.swift @@ -381,9 +381,6 @@ public class DebugFlags: BaseFlags { @objc public static let forceDonorBadgeDisplay = build.includes(.qa) - @objc - public static let forceDonorBadgeAcquisition = build.includes(.qa) - @objc public static let forceSubscriptionMegaphone = build.includes(.qa) diff --git a/SignalServiceKit/src/Util/RemoteConfigManager.swift b/SignalServiceKit/src/Util/RemoteConfigManager.swift index c404e2baf0..69cb255f75 100644 --- a/SignalServiceKit/src/Util/RemoteConfigManager.swift +++ b/SignalServiceKit/src/Util/RemoteConfigManager.swift @@ -202,11 +202,6 @@ public class RemoteConfig: BaseFlags { DebugFlags.forceDonorBadgeDisplay || !isEnabled(.donorBadgeDisplayKillSwitch) } - @objc - public static var donorBadgeAcquisition: Bool { - DebugFlags.forceDonorBadgeAcquisition || !isEnabled(.donorBadgeAcquisitionKillSwitch) - } - @objc public static var changePhoneNumberUI: Bool { if DebugFlags.forceChangePhoneNumberUI.get() { @@ -383,7 +378,8 @@ private struct Flags { // as soon as we fetch an update to the remote config. They will not // wait for an app restart. enum HotSwappableIsEnabledFlags: String, FlagType { - case donorBadgeAcquisitionKillSwitch + // This can't be empty, so we define a bogus case. Remove this if you add a flag here. + case __noHotSwappableIsEnabledFlags } // We filter the received config down to just the supported flags. @@ -400,7 +396,6 @@ private struct Flags { case senderKeyKillSwitch case messageResendKillSwitch case donorBadgeDisplayKillSwitch - case donorBadgeAcquisitionKillSwitch case changePhoneNumberUI }