Path: blob/main/Signal/src/ViewControllers/AppSettings/Payments/PaymentsViewPassphraseGridViewController.swift
1 views
//
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
public import SignalServiceKit
public import SignalUI
public class PaymentsViewPassphraseGridViewController: OWSTableViewController2 {
private let passphrase: PaymentsPassphrase
private weak var viewPassphraseDelegate: PaymentsViewPassphraseDelegate?
private let bottomStack = UIStackView()
override open var bottomFooter: UIView? {
get { bottomStack }
set {}
}
public init(
passphrase: PaymentsPassphrase,
viewPassphraseDelegate: PaymentsViewPassphraseDelegate,
) {
self.passphrase = passphrase
self.viewPassphraseDelegate = viewPassphraseDelegate
super.init()
self.shouldAvoidKeyboard = true
}
override public func viewDidLoad() {
super.viewDidLoad()
title = OWSLocalizedString(
"SETTINGS_PAYMENTS_VIEW_PASSPHRASE_TITLE",
comment: "Title for the 'view payments passphrase' view of the app settings.",
)
buildBottomView()
updateTableContents()
}
override public func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
updateTableContents()
}
override public func themeDidChange() {
super.themeDidChange()
updateTableContents()
}
private func buildBottomView() {
let nextButton = OWSFlatButton.insetButton(
title: CommonStrings.nextButton,
font: UIFont.dynamicTypeHeadline,
titleColor: .white,
backgroundColor: .ows_accentBlue,
target: self,
selector: #selector(didTapNextButton),
)
nextButton.autoSetHeightUsingFont()
bottomStack.axis = .vertical
bottomStack.alignment = .fill
bottomStack.isLayoutMarginsRelativeArrangement = true
bottomStack.layoutMargins = .init(top: 8, left: 20, bottom: 8, right: 20)
bottomStack.addArrangedSubviews([
nextButton,
])
}
private func updateTableContents() {
AssertIsOnMainThread()
let contents = OWSTableContents()
let section = OWSTableSection()
section.customHeaderView = buildHeader()
section.customFooterView = buildFooter()
section.hasBackground = false
section.shouldDisableCellSelection = true
let passphrase = self.passphrase
section.add(OWSTableItem(
customCellBlock: { [weak self] in
let cell = OWSTableItem.newCell()
guard let self else { return cell }
let passphraseGrid = self.buildPassphraseGrid(passphrase: passphrase)
cell.contentView.addSubview(passphraseGrid)
passphraseGrid.autoPinEdgesToSuperviewEdges()
return cell
},
actionBlock: nil,
))
contents.add(section)
self.contents = contents
}
private func buildPassphraseGrid(passphrase: PaymentsPassphrase) -> UIView {
let copyToClipboardLabel = UILabel()
copyToClipboardLabel.text = OWSLocalizedString(
"SETTINGS_PAYMENTS_VIEW_PASSPHRASE_COPY_TO_CLIPBOARD",
comment: "Label for the 'copy to clipboard' button in the 'view payments passphrase' views.",
)
copyToClipboardLabel.textColor = .ows_accentBlue
copyToClipboardLabel.font = UIFont.dynamicTypeSubheadlineClamped.semibold()
let copyToClipboardButton = OWSLayerView.pillView()
copyToClipboardButton.backgroundColor = Theme.secondaryBackgroundColor
copyToClipboardButton.addSubview(copyToClipboardLabel)
copyToClipboardButton.layoutMargins = .init(hMargin: 16, vMargin: 4)
copyToClipboardLabel.autoPinEdgesToSuperviewMargins()
copyToClipboardButton.isUserInteractionEnabled = true
copyToClipboardButton.addGestureRecognizer(UITapGestureRecognizer(
target: self,
action: #selector(showCopyToClipboardConfirmUI),
))
return PaymentsViewUtils.buildPassphraseGrid(
passphrase: passphrase,
footerButton: copyToClipboardButton,
)
}
private func buildHeader() -> UIView {
let explanationLabel = UILabel()
explanationLabel.text = OWSLocalizedString(
"SETTINGS_PAYMENTS_VIEW_PASSPHRASE_WORDS_EXPLANATION",
comment: "Header text for the 'review payments passphrase words' step in the 'view payments passphrase' settings.",
)
explanationLabel.font = .dynamicTypeSubheadlineClamped
explanationLabel.textColor = Theme.secondaryTextAndIconColor
explanationLabel.textAlignment = .center
explanationLabel.numberOfLines = 0
explanationLabel.lineBreakMode = .byWordWrapping
let topStack = UIStackView(arrangedSubviews: [
explanationLabel,
])
topStack.axis = .vertical
topStack.alignment = .center
topStack.isLayoutMarginsRelativeArrangement = true
topStack.layoutMargins = .init(top: 32, left: 20, bottom: 40, right: 20)
return topStack
}
private func buildFooter() -> UIView {
let explanationLabel = UILabel()
explanationLabel.text = OWSLocalizedString(
"SETTINGS_PAYMENTS_VIEW_PASSPHRASE_WORDS_FOOTER_2",
comment: "Footer text for the 'review payments passphrase words' step in the 'view payments passphrase' settings.",
)
explanationLabel.font = .dynamicTypeSubheadlineClamped
explanationLabel.textColor = Theme.secondaryTextAndIconColor
explanationLabel.textAlignment = .center
explanationLabel.numberOfLines = 0
explanationLabel.lineBreakMode = .byWordWrapping
let topStack = UIStackView(arrangedSubviews: [
explanationLabel,
])
topStack.axis = .vertical
topStack.alignment = .center
topStack.isLayoutMarginsRelativeArrangement = true
topStack.layoutMargins = .init(hMargin: 20, vMargin: 16)
return topStack
}
// MARK: - Events
@objc
private func didTapNextButton() {
guard let viewPassphraseDelegate else {
dismiss(animated: false, completion: nil)
return
}
let view = PaymentsViewPassphraseConfirmViewController(
passphrase: passphrase,
viewPassphraseDelegate: viewPassphraseDelegate,
)
navigationController?.pushViewController(view, animated: true)
}
@objc
private func showCopyToClipboardConfirmUI() {
let actionSheet = ActionSheetController(
title: OWSLocalizedString(
"SETTINGS_PAYMENTS_VIEW_PASSPHRASE_COPY_TO_CLIPBOARD_CONFIRM_TITLE",
comment: "Title for the 'copy recovery passphrase to clipboard confirm' alert in the payment settings.",
),
message: OWSLocalizedString(
"SETTINGS_PAYMENTS_VIEW_PASSPHRASE_COPY_TO_CLIPBOARD_CONFIRM_MESSAGE",
comment: "Message for the 'copy recovery passphrase to clipboard confirm' alert in the payment settings.",
),
)
actionSheet.addAction(ActionSheetAction(
title: CommonStrings.copyButton,
style: .default,
) { [weak self] _ in
self?.didTapCopyToClipboard()
})
actionSheet.addAction(OWSActionSheets.cancelAction)
presentActionSheet(actionSheet)
}
@objc
private func didTapCopyToClipboard() {
// Ensure that passphrase only resides in pasteboard for short window of time.
let pasteboardDuration: TimeInterval = .second * 30
let expireDate = Date().addingTimeInterval(pasteboardDuration)
UIPasteboard.general.setItems(
[[UIPasteboard.typeAutomatic: passphrase.asPassphrase]],
options: [.expirationDate: expireDate],
)
self.presentToast(
text: OWSLocalizedString(
"SETTINGS_PAYMENTS_VIEW_PASSPHRASE_COPIED_TO_CLIPBOARD",
comment: "Indicator that the payments passphrase has been copied to the clipboard in the 'view payments passphrase' views.",
),
image: .copy,
extraVInset: bottomStack.height,
)
}
}