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

import Foundation
import SignalServiceKit
import SignalUI
import UIKit

class BadgeDetailsSheet: OWSTableSheetViewController {
    enum Owner: Equatable {
        // TODO: Eventually we won't need a short name for self, the server will provide copy for us.
        case local(shortName: String)
        case remote(shortName: String)

        func formattedDescription(for badge: ProfileBadge) -> String {
            switch self {
            case .local(let shortName):
                return badge.localizedDescriptionFormatString.replacingOccurrences(of: "{short_name}", with: shortName)
            case .remote(let shortName):
                return badge.localizedDescriptionFormatString.replacingOccurrences(of: "{short_name}", with: shortName)
            }
        }

        var isLocal: Bool {
            switch self {
            case .local: return true
            case .remote: return false
            }
        }
    }

    private let owner: Owner
    private let focusedBadge: ProfileBadge

    // TODO: support initializing with a list of available badges and paging between them
    init(focusedBadge: ProfileBadge, owner: Owner) {
        self.focusedBadge = focusedBadge
        self.owner = owner
        super.init()
    }

    // MARK: -

    private var remoteSupporterName: String? {
        guard focusedBadge.category == .donor else {
            return nil
        }

        let isGiftBadge = GiftBadgeIds.contains(focusedBadge.id)
        guard !isGiftBadge else {
            return nil
        }

        switch owner {
        case .local: return nil
        case let .remote(name): return name
        }
    }

    override func tableContents() -> OWSTableContents {
        let contents = OWSTableContents()

        let focusedBadgeSection = OWSTableSection()
        focusedBadgeSection.hasBackground = false
        contents.add(focusedBadgeSection)

        focusedBadgeSection.add(.init(customCellBlock: { [weak self] in
            let cell = OWSTableItem.newCell()
            guard let self else { return cell }
            cell.selectionStyle = .none

            let badgeImageView = UIImageView()
            badgeImageView.image = self.focusedBadge.assets?.universal160
            let badgeImageContainer = UIView.container()
            badgeImageContainer.addSubview(badgeImageView)
            badgeImageView.translatesAutoresizingMaskIntoConstraints = false
            NSLayoutConstraint.activate([
                badgeImageView.widthAnchor.constraint(equalToConstant: 160),
                badgeImageView.heightAnchor.constraint(equalToConstant: 160),

                badgeImageView.leadingAnchor.constraint(greaterThanOrEqualTo: badgeImageContainer.leadingAnchor),
                badgeImageView.centerXAnchor.constraint(equalTo: badgeImageContainer.centerXAnchor),
                badgeImageView.topAnchor.constraint(equalTo: badgeImageContainer.topAnchor),
                badgeImageView.bottomAnchor.constraint(equalTo: badgeImageContainer.bottomAnchor, constant: -16),
            ])

            let text = {
                if let remoteSupporterName = self.remoteSupporterName {
                    let format = OWSLocalizedString(
                        "BADGE_DETAILS_TITLE_FOR_SUPPORTER",
                        comment: "When viewing someone else's donor badge, you'll see a sheet. This is the title on that sheet. Embeds {badge owner's short name}",
                    )
                    return String.nonPluralLocalizedStringWithFormat(format, remoteSupporterName)
                } else {
                    return self.focusedBadge.localizedName
                }
            }()
            let badgeLabel = UILabel.title2Label(text: text)

            let badgeDescription = UILabel.explanationTextLabel(text: self.owner.formattedDescription(for: self.focusedBadge))
            badgeDescription.setCompressionResistanceVerticalHigh()
            badgeDescription.setContentHuggingVerticalHigh()

            let stackView = UIStackView(arrangedSubviews: [
                badgeImageContainer,
                badgeLabel,
                badgeDescription,
            ])
            stackView.setCustomSpacing(36, after: badgeLabel)
            stackView.axis = .vertical
            stackView.alignment = .fill
            cell.contentView.addSubview(stackView)
            stackView.autoPinEdgesToSuperviewEdges()

            return cell
        }, actionBlock: nil))

        if !owner.isLocal {
            let buttonSection = OWSTableSection(items: [.init(customCellBlock: { [weak self] in
                let cell = OWSTableItem.newCell()
                cell.selectionStyle = .none

                guard let self else { return cell }
                let button = UIButton(
                    configuration: .largePrimary(title: OWSLocalizedString(
                        "BADGE_DETAILS_DONATE_TO_SIGNAL",
                        comment: "When viewing someone else's badge, you'll see a sheet. If they got the badge by donating, a \"Donate to Signal\" button will be shown. This is the text in that button.",
                    )),
                    primaryAction: UIAction { [weak self] _ in
                        self?.didTapDonate()
                    },
                )
                let buttonContainer = button.enclosedInVerticalStackView(isFullWidthButton: true)
                buttonContainer.directionalLayoutMargins.top = 16
                cell.contentView.addSubview(buttonContainer)
                buttonContainer.autoPinEdgesToSuperviewEdges()

                return cell
            })])
            buttonSection.hasBackground = false
            contents.add(buttonSection)
        }

        return contents
    }

    private func didTapDonate() {
        dismiss(animated: true) {
            if
                DonationUtilities.canDonateInAnyWay(
                    tsAccountManager: DependenciesBridge.shared.tsAccountManager,
                )
            {
                let frontVc = { CurrentAppContext().frontmostViewController() }

                let donateVc = DonateViewController(preferredDonateMode: .oneTime) { finishResult in
                    switch finishResult {
                    case let .completedDonation(donateSheet, receiptCredentialSuccessMode):
                        donateSheet.dismiss(animated: true) {
                            guard
                                let frontVc = frontVc(),
                                let badgeThanksSheetPresenter = BadgeThanksSheetPresenter.fromGlobalsWithSneakyTransaction(
                                    successMode: receiptCredentialSuccessMode,
                                )
                            else { return }

                            Task {
                                await badgeThanksSheetPresenter.presentAndRecordBadgeThanks(
                                    fromViewController: frontVc,
                                )
                            }
                        }
                    case let .monthlySubscriptionCancelled(donateSheet, toastText):
                        donateSheet.dismiss(animated: true) {
                            frontVc()?.presentToast(text: toastText)
                        }
                    }
                }
                let navigationVc = OWSNavigationController(rootViewController: donateVc)
                frontVc()?.present(navigationVc, animated: true)
            } else {
                DonationViewsUtil.openDonateWebsite()
            }
        }
    }
}