Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
signalapp
GitHub Repository: signalapp/Signal-iOS
Path: blob/main/Signal/src/ViewControllers/AppSettings/Payments/PaymentsDeactivateViewController.swift
1 views
//
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//

import SignalServiceKit
public import SignalUI

public class PaymentsDeactivateViewController: OWSViewController {

    var paymentBalance: PaymentBalance

    public init(paymentBalance: PaymentBalance) {
        owsAssertDebug(paymentBalance.amount.isValidAmount(canBeEmpty: false))

        self.paymentBalance = paymentBalance
        super.init()
    }

    override public func viewDidLoad() {
        super.viewDidLoad()

        title = OWSLocalizedString(
            "SETTINGS_PAYMENTS_DEACTIVATE_TITLE",
            comment: "Label for the 'de-activate payments' view of the app settings.",
        )

        navigationItem.leftBarButtonItem = UIBarButtonItem(
            barButtonSystemItem: .done,
            target: self,
            action: #selector(didTapDismiss),
            accessibilityIdentifier: "dismiss",
        )

        addListeners()

        updateContents()
    }

    override public func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        SUIEnvironment.shared.paymentsSwiftRef.updateCurrentPaymentBalance()
    }

    override public func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        updateContents()
    }

    override public func themeDidChange() {
        super.themeDidChange()

        updateContents()
    }

    private func addListeners() {
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(arePaymentsEnabledDidChange),
            name: PaymentsConstants.arePaymentsEnabledDidChange,
            object: nil,
        )
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(currentPaymentBalanceDidChange),
            name: PaymentsImpl.currentPaymentBalanceDidChange,
            object: nil,
        )
    }

    @objc
    private func arePaymentsEnabledDidChange() {
        Logger.info("")
        dismiss(animated: true, completion: nil)
    }

    @objc
    private func currentPaymentBalanceDidChange() {
        guard
            let currentPaymentBalance = SUIEnvironment.shared.paymentsSwiftRef.currentPaymentBalance,
            currentPaymentBalance.amount.isValidAmount(canBeEmpty: false)
        else {
            // We need to abort the "deactivate payments with outstanding balance"
            // flow if:
            //
            // * The balance becomes unavailable (this should never happen).
            // * The balance becomes zero (this should be extremely rare).
            Logger.warn("Missing or empty balance.")
            dismiss(animated: true, completion: nil)
            return
        }
        self.paymentBalance = currentPaymentBalance
        self.updateContents()
    }

    private func updateContents() {
        let backgroundColor = OWSTableViewController2.tableBackgroundColor(isUsingPresentedStyle: true)
        view.backgroundColor = backgroundColor

        view.removeAllSubviews()

        let titleLabel = UILabel()
        titleLabel.font = UIFont.regularFont(ofSize: 54)
        titleLabel.textColor = Theme.primaryTextColor
        titleLabel.attributedText = PaymentsFormat.attributedFormat(
            paymentAmount: paymentBalance.amount,
            isShortForm: false,
        )
        titleLabel.adjustsFontSizeToFitWidth = true
        titleLabel.textAlignment = .center

        let subtitleLabel = UILabel()
        subtitleLabel.text = OWSLocalizedString(
            "SETTINGS_PAYMENTS_REMAINING_BALANCE",
            comment: "Label for the current balance in the 'deactivate payments' settings.",
        )
        subtitleLabel.font = .dynamicTypeBodyClamped
        subtitleLabel.textColor = Theme.secondaryTextAndIconColor
        subtitleLabel.textAlignment = .center

        let explanationLabel = PaymentsViewUtils.buildTextWithLearnMoreLinkTextView(
            text: OWSLocalizedString(
                "SETTINGS_PAYMENTS_DEACTIVATE_WITH_BALANCE_EXPLANATION",
                comment: "Explanation of the 'deactivate payments with balance' process in the 'deactivate payments' settings.",
            ),
            font: .dynamicTypeSubheadlineClamped,
            learnMoreUrl: URL.Support.Payments.deactivate,
        )
        explanationLabel.backgroundColor = backgroundColor
        explanationLabel.textAlignment = .center

        let transferBalanceButton = OWSFlatButton.button(
            title: OWSLocalizedString(
                "SETTINGS_PAYMENTS_DEACTIVATE_AFTER_TRANSFERRING_BALANCE",
                comment: "Label for 'transfer balance' button in the 'deactivate payments' settings.",
            ),
            font: UIFont.dynamicTypeHeadline,
            titleColor: .white,
            backgroundColor: .ows_accentBlue,
            target: self,
            selector: #selector(didTapTransferBalanceButton),
        )
        transferBalanceButton.autoSetHeightUsingFont()

        let deactivateImmediatelyButton = OWSFlatButton.button(
            title: OWSLocalizedString(
                "SETTINGS_PAYMENTS_DEACTIVATE_WITHOUT_TRANSFERRING_BALANCE",
                comment: "Label for 'deactivate payments without transferring balance' button in the 'deactivate payments' settings.",
            ),
            font: UIFont.dynamicTypeHeadline,
            titleColor: .ows_accentRed,
            backgroundColor: backgroundColor,
            target: self,
            selector: #selector(didTapDeactivateImmediatelyButton),
        )
        deactivateImmediatelyButton.autoSetHeightUsingFont()

        let topStack = UIStackView(arrangedSubviews: [
            titleLabel,
            UIView.spacer(withHeight: 8),
            subtitleLabel,
            UIView.spacer(withHeight: 44),
            explanationLabel,
        ])
        topStack.axis = .vertical
        topStack.alignment = .center
        topStack.isLayoutMarginsRelativeArrangement = true
        topStack.layoutMargins = UIEdgeInsets(hMargin: 20, vMargin: 0)

        let stackView = UIStackView(arrangedSubviews: [
            UIView.spacer(withHeight: 40),
            topStack,
            UIView.vStretchingSpacer(),
            transferBalanceButton,
            UIView.spacer(withHeight: 8),
            deactivateImmediatelyButton,
            UIView.spacer(withHeight: 8),
        ])
        stackView.axis = .vertical
        stackView.alignment = .fill
        view.addSubview(stackView)
        stackView.autoPinWidthToSuperviewMargins()
        stackView.autoPin(toTopLayoutGuideOf: self, withInset: 0)
        stackView.autoPin(toBottomLayoutGuideOf: self, withInset: 0)
    }

    // MARK: - Events

    @objc
    private func didTapTransferBalanceButton() {
        ModalActivityIndicatorViewController.present(
            fromViewController: self,
            canCancel: false,
            asyncBlock: { modalActivityIndicator in
                do {
                    let transferAmount = try await SUIEnvironment.shared.paymentsSwiftRef.maximumPaymentAmount()
                    modalActivityIndicator.dismiss {
                        guard let navigationController = self.navigationController else {
                            owsFailDebug("Missing navigationController.")
                            return
                        }
                        let view = PaymentsTransferOutViewController(transferAmount: transferAmount)
                        navigationController.pushViewController(view, animated: true)
                    }
                } catch {
                    owsFailDebug("Error: \(error)")

                    modalActivityIndicator.dismiss {
                        OWSActionSheets.showErrorAlert(message: OWSLocalizedString(
                            "SETTINGS_PAYMENTS_DEACTIVATION_FAILED",
                            comment: "Error indicating that payments could not be deactivated in the payments settings.",
                        ))
                    }
                }
            },
        )
    }

    @objc
    private func didTapDeactivateImmediatelyButton() {
        let actionSheet = ActionSheetController(
            title: OWSLocalizedString(
                "SETTINGS_PAYMENTS_DEACTIVATE_WITHOUT_TRANSFER_CONFIRM_TITLE",
                comment: "Title for the 'deactivate payments confirmation' UI in the payment settings.",
            ),
            message: OWSLocalizedString(
                "SETTINGS_PAYMENTS_DEACTIVATE_WITHOUT_TRANSFER_CONFIRM_DESCRIPTION",
                comment: "Description for the 'deactivate payments confirmation' UI in the payment settings.",
            ),
        )

        actionSheet.addAction(ActionSheetAction(
            title: OWSLocalizedString(
                "SETTINGS_PAYMENTS_DEACTIVATE_BUTTON",
                comment: "Label for the 'deactivate payments' button in the payment settings.",
            ),
            style: .destructive,
        ) { [weak self] _ in
            self?.deactivateImmediately()
        })

        actionSheet.addAction(OWSActionSheets.cancelAction)

        presentActionSheet(actionSheet)
    }

    private func deactivateImmediately() {
        dismiss(animated: true) {
            SSKEnvironment.shared.databaseStorageRef.write { transaction in
                SSKEnvironment.shared.paymentsHelperRef.disablePayments(transaction: transaction)
            }
        }
    }

    @objc
    private func didTapDismiss() {
        dismiss(animated: true, completion: nil)
    }
}