parent
3ce77d553f
commit
2ece6a6624
@ -0,0 +1,84 @@ |
||||
// Copyright © 2018 Stormbird PTE. LTD. |
||||
|
||||
import UIKit |
||||
|
||||
struct GenerateTransferMagicLinkViewControllerViewModel { |
||||
var ticketHolder: TicketHolder |
||||
var linkExpiryDate: Date |
||||
|
||||
var contentsBackgroundColor: UIColor { |
||||
return Colors.appWhite |
||||
} |
||||
var subtitleColor: UIColor { |
||||
return Colors.appText |
||||
} |
||||
var subtitleFont: UIFont { |
||||
return Fonts.light(size: 25)! |
||||
} |
||||
var subtitleLabelText: String { |
||||
return R.string.localizable.aWalletTicketTokenSellConfirmSubtitle() |
||||
} |
||||
|
||||
var headerTitle: String { |
||||
return R.string.localizable.aWalletTicketTokenSellConfirmTitle() |
||||
} |
||||
|
||||
var actionButtonTitleColor: UIColor { |
||||
return Colors.appWhite |
||||
} |
||||
var actionButtonBackgroundColor: UIColor { |
||||
return Colors.appBackground |
||||
} |
||||
var actionButtonTitleFont: UIFont { |
||||
return Fonts.regular(size: 20)! |
||||
} |
||||
var cancelButtonTitleColor: UIColor { |
||||
return Colors.appRed |
||||
} |
||||
var cancelButtonBackgroundColor: UIColor { |
||||
return .clear |
||||
} |
||||
var cancelButtonTitleFont: UIFont { |
||||
return Fonts.regular(size: 20)! |
||||
} |
||||
var actionButtonTitle: String { |
||||
return R.string.localizable.aWalletTicketTokenSellConfirmButtonTitle() |
||||
} |
||||
var cancelButtonTitle: String { |
||||
return R.string.localizable.aWalletTicketTokenSellConfirmCancelButtonTitle() |
||||
} |
||||
|
||||
var ticketSaleDetailsLabelFont: UIFont { |
||||
return Fonts.semibold(size: 21)! |
||||
} |
||||
|
||||
var ticketSaleDetailsLabelColor: UIColor { |
||||
return Colors.appBackground |
||||
} |
||||
|
||||
var descriptionLabelText: String { |
||||
//TODO Should format be localized? |
||||
return R.string.localizable.aWalletTicketTokenSellConfirmExpiryDateDescription(linkExpiryDate.format("dd MMM yyyy hh:mm")) |
||||
} |
||||
|
||||
var ticketCountLabelText: String { |
||||
if ticketCount == 1 { |
||||
return R.string.localizable.aWalletTicketTokenSellConfirmSingleTicketSelectedTitle() |
||||
} else { |
||||
return R.string.localizable.aWalletTicketTokenSellConfirmMultipleTicketSelectedTitle(ticketHolder.ticketCount) |
||||
} |
||||
} |
||||
|
||||
var detailsBackgroundBackgroundColor: UIColor { |
||||
return UIColor(red: 236, green: 236, blue: 236) |
||||
} |
||||
|
||||
private var ticketCount: Int { |
||||
return Int(ticketHolder.ticketCount)! |
||||
} |
||||
|
||||
init(ticketHolder: TicketHolder, linkExpiryDate: Date) { |
||||
self.ticketHolder = ticketHolder |
||||
self.linkExpiryDate = linkExpiryDate |
||||
} |
||||
} |
@ -1,49 +0,0 @@ |
||||
// Copyright © 2018 Stormbird PTE. LTD. |
||||
|
||||
import Foundation |
||||
import QRCodeReaderViewController |
||||
|
||||
protocol ScanQRCodeForWalletAddressToTransferTicketCoordinatorDelegate: class { |
||||
func scanned(walletAddress: String, in coordinator: ScanQRCodeForWalletAddressToTransferTicketCoordinator) |
||||
func cancelled(in coordinator: ScanQRCodeForWalletAddressToTransferTicketCoordinator) |
||||
} |
||||
|
||||
class ScanQRCodeForWalletAddressToTransferTicketCoordinator: NSObject, Coordinator { |
||||
var coordinators: [Coordinator] = [] |
||||
var ticketHolder: TicketHolder |
||||
var viewController: UIViewController |
||||
var paymentFlow: PaymentFlow |
||||
weak var delegate: ScanQRCodeForWalletAddressToTransferTicketCoordinatorDelegate? |
||||
|
||||
init(ticketHolder: TicketHolder, paymentFlow: PaymentFlow, in viewController: UIViewController) { |
||||
self.ticketHolder = ticketHolder |
||||
self.paymentFlow = paymentFlow |
||||
self.viewController = viewController |
||||
} |
||||
|
||||
func start() { |
||||
let controller = QRCodeReaderViewController() |
||||
controller.delegate = self |
||||
viewController.present(controller, animated: true, completion: nil) |
||||
} |
||||
} |
||||
|
||||
extension ScanQRCodeForWalletAddressToTransferTicketCoordinator: QRCodeReaderDelegate { |
||||
func readerDidCancel(_ reader: QRCodeReaderViewController!) { |
||||
reader.stopScanning() |
||||
reader.dismiss(animated: true) { [weak self] in |
||||
if let celf = self { |
||||
celf.delegate?.cancelled(in: celf) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func reader(_ reader: QRCodeReaderViewController!, didScanResult result: String!) { |
||||
reader.stopScanning() |
||||
reader.dismiss(animated: true) { [weak self] in |
||||
if let celf = self { |
||||
celf.delegate?.scanned(walletAddress: result, in: celf) |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,159 @@ |
||||
// Copyright © 2018 Stormbird PTE. LTD. |
||||
|
||||
import Foundation |
||||
import UIKit |
||||
|
||||
protocol GenerateTransferMagicLinkViewControllerDelegate: class { |
||||
func didPressShare(in viewController: GenerateTransferMagicLinkViewController, sender: UIView) |
||||
func didPressCancel(in viewController: GenerateTransferMagicLinkViewController) |
||||
} |
||||
|
||||
class GenerateTransferMagicLinkViewController: UIViewController { |
||||
weak var delegate: GenerateTransferMagicLinkViewControllerDelegate? |
||||
let background = UIView() |
||||
let header = TicketsViewControllerTitleHeader() |
||||
let detailsBackground = UIView() |
||||
let subtitleLabel = UILabel() |
||||
let ticketCountLabel = UILabel() |
||||
let descriptionLabel = UILabel() |
||||
let actionButton = UIButton() |
||||
let cancelButton = UIButton() |
||||
var paymentFlow: PaymentFlow |
||||
var ticketHolder: TicketHolder |
||||
var linkExpiryDate: Date |
||||
var viewModel: GenerateTransferMagicLinkViewControllerViewModel? |
||||
|
||||
init(paymentFlow: PaymentFlow, ticketHolder: TicketHolder, linkExpiryDate: Date) { |
||||
self.paymentFlow = paymentFlow |
||||
self.ticketHolder = ticketHolder |
||||
self.linkExpiryDate = linkExpiryDate |
||||
super.init(nibName: nil, bundle: nil) |
||||
view.backgroundColor = .clear |
||||
|
||||
let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark)) |
||||
visualEffectView.translatesAutoresizingMaskIntoConstraints = false |
||||
view.insertSubview(visualEffectView, at: 0) |
||||
|
||||
view.addSubview(background) |
||||
background.translatesAutoresizingMaskIntoConstraints = false |
||||
|
||||
ticketCountLabel.translatesAutoresizingMaskIntoConstraints = false |
||||
descriptionLabel.translatesAutoresizingMaskIntoConstraints = false |
||||
|
||||
detailsBackground.translatesAutoresizingMaskIntoConstraints = false |
||||
background.addSubview(detailsBackground) |
||||
|
||||
actionButton.addTarget(self, action: #selector(share), for: .touchUpInside) |
||||
cancelButton.addTarget(self, action: #selector(cancel), for: .touchUpInside) |
||||
|
||||
let stackView = UIStackView(arrangedSubviews: [ |
||||
header, |
||||
.spacer(height: 20), |
||||
subtitleLabel, |
||||
ticketCountLabel, |
||||
.spacer(height: 20), |
||||
descriptionLabel, |
||||
.spacer(height: 30), |
||||
actionButton, |
||||
.spacer(height: 10), |
||||
cancelButton, |
||||
.spacer(height: 1) |
||||
]) |
||||
stackView.translatesAutoresizingMaskIntoConstraints = false |
||||
stackView.axis = .vertical |
||||
stackView.spacing = 0 |
||||
stackView.distribution = .fill |
||||
background.addSubview(stackView) |
||||
|
||||
NSLayoutConstraint.activate([ |
||||
header.heightAnchor.constraint(equalToConstant: 60), |
||||
//Strange repositioning of header horizontally while typing without this |
||||
header.leadingAnchor.constraint(equalTo: stackView.leadingAnchor), |
||||
header.trailingAnchor.constraint(equalTo: stackView.trailingAnchor), |
||||
|
||||
visualEffectView.leadingAnchor.constraint(equalTo: view.leadingAnchor), |
||||
visualEffectView.trailingAnchor.constraint(equalTo: view.trailingAnchor), |
||||
visualEffectView.topAnchor.constraint(equalTo: view.topAnchor), |
||||
visualEffectView.bottomAnchor.constraint(equalTo: view.bottomAnchor), |
||||
|
||||
detailsBackground.leadingAnchor.constraint(equalTo: background.leadingAnchor), |
||||
detailsBackground.trailingAnchor.constraint(equalTo: background.trailingAnchor), |
||||
detailsBackground.topAnchor.constraint(equalTo: subtitleLabel.topAnchor, constant: -12), |
||||
detailsBackground.bottomAnchor.constraint(equalTo: descriptionLabel.bottomAnchor, constant: 12), |
||||
|
||||
actionButton.heightAnchor.constraint(equalToConstant: 47), |
||||
cancelButton.heightAnchor.constraint(equalTo: actionButton.heightAnchor), |
||||
|
||||
stackView.leadingAnchor.constraint(equalTo: background.leadingAnchor, constant: 40), |
||||
stackView.trailingAnchor.constraint(equalTo: background.trailingAnchor, constant: -40), |
||||
stackView.topAnchor.constraint(equalTo: background.topAnchor, constant: 16), |
||||
stackView.bottomAnchor.constraint(equalTo: background.bottomAnchor, constant: -16), |
||||
|
||||
background.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 42), |
||||
background.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -42), |
||||
background.centerYAnchor.constraint(equalTo: view.centerYAnchor) |
||||
]) |
||||
} |
||||
|
||||
required init?(coder aDecoder: NSCoder) { |
||||
fatalError("init(coder:) has not been implemented") |
||||
} |
||||
|
||||
func configure(viewModel: GenerateTransferMagicLinkViewControllerViewModel) { |
||||
self.viewModel = viewModel |
||||
if let viewModel = self.viewModel { |
||||
background.backgroundColor = viewModel.contentsBackgroundColor |
||||
background.layer.cornerRadius = 20 |
||||
|
||||
header.configure(title: viewModel.headerTitle) |
||||
|
||||
subtitleLabel.numberOfLines = 0 |
||||
subtitleLabel.textColor = viewModel.subtitleColor |
||||
subtitleLabel.font = viewModel.subtitleFont |
||||
subtitleLabel.textAlignment = .center |
||||
subtitleLabel.text = viewModel.subtitleLabelText |
||||
|
||||
ticketCountLabel.textAlignment = .center |
||||
ticketCountLabel.textColor = viewModel.ticketSaleDetailsLabelColor |
||||
ticketCountLabel.font = viewModel.ticketSaleDetailsLabelFont |
||||
ticketCountLabel.text = viewModel.ticketCountLabelText |
||||
|
||||
descriptionLabel.textAlignment = .center |
||||
descriptionLabel.numberOfLines = 0 |
||||
descriptionLabel.textColor = viewModel.ticketSaleDetailsLabelColor |
||||
descriptionLabel.font = viewModel.ticketSaleDetailsLabelFont |
||||
descriptionLabel.text = viewModel.descriptionLabelText |
||||
|
||||
detailsBackground.backgroundColor = viewModel.detailsBackgroundBackgroundColor |
||||
|
||||
actionButton.setTitleColor(viewModel.actionButtonTitleColor, for: .normal) |
||||
actionButton.setBackgroundColor(viewModel.actionButtonBackgroundColor, forState: .normal) |
||||
actionButton.titleLabel?.font = viewModel.actionButtonTitleFont |
||||
actionButton.setTitle(viewModel.actionButtonTitle, for: .normal) |
||||
actionButton.layer.masksToBounds = true |
||||
|
||||
cancelButton.setTitleColor(viewModel.cancelButtonTitleColor, for: .normal) |
||||
cancelButton.setBackgroundColor(viewModel.cancelButtonBackgroundColor, forState: .normal) |
||||
cancelButton.titleLabel?.font = viewModel.cancelButtonTitleFont |
||||
cancelButton.setTitle(viewModel.cancelButtonTitle, for: .normal) |
||||
cancelButton.layer.masksToBounds = true |
||||
} |
||||
} |
||||
|
||||
override func viewDidLayoutSubviews() { |
||||
super.viewDidLayoutSubviews() |
||||
actionButton.layer.cornerRadius = actionButton.frame.size.height / 2 |
||||
} |
||||
|
||||
@objc func share() { |
||||
delegate?.didPressShare(in: self, sender: actionButton) |
||||
} |
||||
|
||||
@objc func cancel() { |
||||
if let delegate = delegate { |
||||
delegate.didPressCancel(in: self) |
||||
} else { |
||||
dismiss(animated: true) |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,336 @@ |
||||
// Copyright © 2018 Stormbird PTE. LTD. |
||||
|
||||
import UIKit |
||||
|
||||
protocol SetTransferTicketsExpiryDateViewControllerDelegate: class { |
||||
func didPressNext(ticketHolder: TicketHolder, linkExpiryDate: Date, in viewController: SetTransferTicketsExpiryDateViewController) |
||||
func didPressViewInfo(in viewController: SetTransferTicketsExpiryDateViewController) |
||||
} |
||||
|
||||
class SetTransferTicketsExpiryDateViewController: UIViewController { |
||||
|
||||
//roundedBackground is used to achieve the top 2 rounded corners-only effect since maskedCorners to not round bottom corners is not available in iOS 10 |
||||
let roundedBackground = UIView() |
||||
let scrollView = UIScrollView() |
||||
let header = TicketsViewControllerTitleHeader() |
||||
let ticketView = TicketRowView() |
||||
let linkExpiryDateLabel = UILabel() |
||||
let linkExpiryDateField = DateEntryField() |
||||
let linkExpiryTimeLabel = UILabel() |
||||
let linkExpiryTimeField = TimeEntryField() |
||||
var datePicker = UIDatePicker() |
||||
var timePicker = UIDatePicker() |
||||
let descriptionLabel = UILabel() |
||||
let noteTitleLabel = UILabel() |
||||
let noteLabel = UILabel() |
||||
let noteBorderView = UIView() |
||||
let nextButton = UIButton(type: .system) |
||||
var viewModel: SetTransferTicketsExpiryDateViewControllerViewModel! |
||||
var ticketHolder: TicketHolder |
||||
var paymentFlow: PaymentFlow |
||||
weak var delegate: SetTransferTicketsExpiryDateViewControllerDelegate? |
||||
|
||||
init(ticketHolder: TicketHolder, paymentFlow: PaymentFlow) { |
||||
self.ticketHolder = ticketHolder |
||||
self.paymentFlow = paymentFlow |
||||
super.init(nibName: nil, bundle: nil) |
||||
|
||||
navigationItem.rightBarButtonItem = UIBarButtonItem(image: R.image.location(), style: .plain, target: self, action: #selector(showInfo)) |
||||
|
||||
roundedBackground.translatesAutoresizingMaskIntoConstraints = false |
||||
roundedBackground.backgroundColor = Colors.appWhite |
||||
roundedBackground.cornerRadius = 20 |
||||
view.addSubview(roundedBackground) |
||||
|
||||
scrollView.translatesAutoresizingMaskIntoConstraints = false |
||||
roundedBackground.addSubview(scrollView) |
||||
|
||||
linkExpiryDateLabel.translatesAutoresizingMaskIntoConstraints = false |
||||
linkExpiryTimeLabel.translatesAutoresizingMaskIntoConstraints = false |
||||
|
||||
nextButton.setTitle(R.string.localizable.aWalletNextButtonTitle(), for: .normal) |
||||
nextButton.addTarget(self, action: #selector(nextButtonTapped), for: .touchUpInside) |
||||
|
||||
ticketView.translatesAutoresizingMaskIntoConstraints = false |
||||
scrollView.addSubview(ticketView) |
||||
|
||||
descriptionLabel.translatesAutoresizingMaskIntoConstraints = false |
||||
noteTitleLabel.translatesAutoresizingMaskIntoConstraints = false |
||||
noteLabel.translatesAutoresizingMaskIntoConstraints = false |
||||
|
||||
noteBorderView.translatesAutoresizingMaskIntoConstraints = false |
||||
scrollView.addSubview(noteBorderView) |
||||
|
||||
let col0 = UIStackView(arrangedSubviews: [ |
||||
linkExpiryDateLabel, |
||||
.spacer(height: 4), |
||||
linkExpiryDateField, |
||||
]) |
||||
col0.translatesAutoresizingMaskIntoConstraints = false |
||||
col0.axis = .vertical |
||||
col0.spacing = 0 |
||||
col0.distribution = .fill |
||||
|
||||
let col1 = UIStackView(arrangedSubviews: [ |
||||
linkExpiryTimeLabel, |
||||
.spacer(height: 4), |
||||
linkExpiryTimeField, |
||||
]) |
||||
col1.translatesAutoresizingMaskIntoConstraints = false |
||||
col1.axis = .vertical |
||||
col1.spacing = 0 |
||||
col1.distribution = .fill |
||||
|
||||
let choicesStackView = UIStackView(arrangedSubviews: [ |
||||
col0, |
||||
.spacerWidth(10), |
||||
col1, |
||||
]) |
||||
choicesStackView.translatesAutoresizingMaskIntoConstraints = false |
||||
choicesStackView.axis = .horizontal |
||||
choicesStackView.spacing = 0 |
||||
choicesStackView.distribution = .fill |
||||
|
||||
let noteStackView = UIStackView(arrangedSubviews: [ |
||||
noteTitleLabel, |
||||
.spacer(height: 4), |
||||
noteLabel, |
||||
]) |
||||
noteStackView.translatesAutoresizingMaskIntoConstraints = false |
||||
noteStackView.axis = .vertical |
||||
noteStackView.spacing = 0 |
||||
noteStackView.distribution = .fill |
||||
noteBorderView.addSubview(noteStackView) |
||||
|
||||
datePicker.datePickerMode = .date |
||||
datePicker.minimumDate = Date() |
||||
datePicker.addTarget(self, action: #selector(datePickerValueChanged), for: .valueChanged) |
||||
datePicker.isHidden = true |
||||
|
||||
timePicker.datePickerMode = .time |
||||
timePicker.minimumDate = Date.yesterday |
||||
timePicker.addTarget(self, action: #selector(timePickerValueChanged), for: .valueChanged) |
||||
timePicker.isHidden = true |
||||
|
||||
let stackView = UIStackView(arrangedSubviews: [ |
||||
header, |
||||
ticketView, |
||||
.spacer(height: 18), |
||||
descriptionLabel, |
||||
.spacer(height: 18), |
||||
choicesStackView, |
||||
datePicker, |
||||
timePicker, |
||||
.spacer(height: 10), |
||||
noteBorderView, |
||||
]) |
||||
stackView.translatesAutoresizingMaskIntoConstraints = false |
||||
stackView.axis = .vertical |
||||
stackView.spacing = 0 |
||||
stackView.distribution = .fill |
||||
stackView.alignment = .center |
||||
scrollView.addSubview(stackView) |
||||
|
||||
linkExpiryDateField.translatesAutoresizingMaskIntoConstraints = false |
||||
linkExpiryDateField.value = Date.tomorrow |
||||
linkExpiryDateField.delegate = self |
||||
|
||||
linkExpiryTimeField.translatesAutoresizingMaskIntoConstraints = false |
||||
linkExpiryTimeField.delegate = self |
||||
|
||||
let buttonsStackView = UIStackView(arrangedSubviews: [nextButton]) |
||||
buttonsStackView.translatesAutoresizingMaskIntoConstraints = false |
||||
buttonsStackView.axis = .horizontal |
||||
buttonsStackView.spacing = 0 |
||||
buttonsStackView.distribution = .fillEqually |
||||
buttonsStackView.setContentHuggingPriority(.required, for: .horizontal) |
||||
|
||||
let marginToHideBottomRoundedCorners = CGFloat(30) |
||||
let footerBar = UIView() |
||||
footerBar.translatesAutoresizingMaskIntoConstraints = false |
||||
footerBar.backgroundColor = Colors.appHighlightGreen |
||||
roundedBackground.addSubview(footerBar) |
||||
|
||||
let buttonsHeight = CGFloat(60) |
||||
footerBar.addSubview(buttonsStackView) |
||||
|
||||
NSLayoutConstraint.activate([ |
||||
header.heightAnchor.constraint(equalToConstant: 90), |
||||
|
||||
ticketView.leadingAnchor.constraint(equalTo: view.leadingAnchor), |
||||
ticketView.trailingAnchor.constraint(equalTo: view.trailingAnchor), |
||||
|
||||
roundedBackground.leadingAnchor.constraint(equalTo: view.leadingAnchor), |
||||
roundedBackground.trailingAnchor.constraint(equalTo: view.trailingAnchor), |
||||
roundedBackground.topAnchor.constraint(equalTo: view.topAnchor), |
||||
roundedBackground.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: marginToHideBottomRoundedCorners), |
||||
|
||||
linkExpiryDateField.leadingAnchor.constraint(equalTo: ticketView.background.leadingAnchor), |
||||
linkExpiryTimeField.rightAnchor.constraint(equalTo: ticketView.background.rightAnchor), |
||||
linkExpiryDateField.heightAnchor.constraint(equalToConstant: 50), |
||||
linkExpiryDateField.widthAnchor.constraint(equalTo: linkExpiryTimeField.widthAnchor), |
||||
linkExpiryDateField.heightAnchor.constraint(equalTo: linkExpiryTimeField.heightAnchor), |
||||
|
||||
datePicker.leadingAnchor.constraint(equalTo: ticketView.background.leadingAnchor), |
||||
datePicker.trailingAnchor.constraint(equalTo: ticketView.background.trailingAnchor), |
||||
|
||||
timePicker.leadingAnchor.constraint(equalTo: ticketView.background.leadingAnchor), |
||||
timePicker.trailingAnchor.constraint(equalTo: ticketView.background.trailingAnchor), |
||||
|
||||
noteBorderView.leadingAnchor.constraint(equalTo: ticketView.background.leadingAnchor), |
||||
noteBorderView.trailingAnchor.constraint(equalTo: ticketView.background.trailingAnchor), |
||||
|
||||
noteStackView.leadingAnchor.constraint(equalTo: noteBorderView.leadingAnchor, constant: 10), |
||||
noteStackView.trailingAnchor.constraint(equalTo: noteBorderView.trailingAnchor, constant: -10), |
||||
noteStackView.topAnchor.constraint(equalTo: noteBorderView.topAnchor, constant: 10), |
||||
noteStackView.bottomAnchor.constraint(equalTo: noteBorderView.bottomAnchor, constant: -10), |
||||
|
||||
stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor), |
||||
stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor), |
||||
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor), |
||||
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor), |
||||
|
||||
buttonsStackView.leadingAnchor.constraint(equalTo: footerBar.leadingAnchor), |
||||
buttonsStackView.trailingAnchor.constraint(equalTo: footerBar.trailingAnchor), |
||||
buttonsStackView.topAnchor.constraint(equalTo: footerBar.topAnchor), |
||||
buttonsStackView.heightAnchor.constraint(equalToConstant: buttonsHeight), |
||||
|
||||
footerBar.leadingAnchor.constraint(equalTo: view.leadingAnchor), |
||||
footerBar.trailingAnchor.constraint(equalTo: view.trailingAnchor), |
||||
footerBar.heightAnchor.constraint(equalToConstant: buttonsHeight), |
||||
footerBar.bottomAnchor.constraint(equalTo: view.bottomAnchor), |
||||
|
||||
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor), |
||||
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor), |
||||
scrollView.topAnchor.constraint(equalTo: view.topAnchor), |
||||
scrollView.bottomAnchor.constraint(equalTo: footerBar.topAnchor), |
||||
]) |
||||
} |
||||
|
||||
required init?(coder aDecoder: NSCoder) { |
||||
fatalError("init(coder:) has not been implemented") |
||||
} |
||||
|
||||
@objc func nextButtonTapped() { |
||||
let expiryDate = linkExpiryDate() |
||||
guard expiryDate > Date() else { |
||||
UIAlertController.alert(title: "", |
||||
message: R.string.localizable.aWalletTicketTokenTransferLinkExpiryTimeAtLeastNowTitle(), |
||||
alertButtonTitles: [R.string.localizable.oK()], |
||||
alertButtonStyles: [.cancel], |
||||
viewController: self, |
||||
completion: nil) |
||||
return |
||||
} |
||||
|
||||
delegate?.didPressNext(ticketHolder: ticketHolder, linkExpiryDate: expiryDate, in: self) |
||||
} |
||||
|
||||
private func linkExpiryDate() -> Date { |
||||
let hour = NSCalendar.current.component(.hour, from: linkExpiryTimeField.value) |
||||
let minutes = NSCalendar.current.component(.minute, from: linkExpiryTimeField.value) |
||||
let seconds = NSCalendar.current.component(.second, from: linkExpiryTimeField.value) |
||||
if let date = NSCalendar.current.date(bySettingHour: hour, minute: minutes, second: seconds, of: linkExpiryDateField.value) { |
||||
return date |
||||
} else { |
||||
return Date() |
||||
} |
||||
} |
||||
|
||||
@objc func showInfo() { |
||||
delegate?.didPressViewInfo(in: self) |
||||
} |
||||
|
||||
override func viewDidLayoutSubviews() { |
||||
super.viewDidLayoutSubviews() |
||||
linkExpiryDateField.layer.cornerRadius = linkExpiryDateField.frame.size.height / 2 |
||||
linkExpiryTimeField.layer.cornerRadius = linkExpiryTimeField.frame.size.height / 2 |
||||
} |
||||
|
||||
@objc func datePickerValueChanged() { |
||||
linkExpiryDateField.value = datePicker.date |
||||
} |
||||
|
||||
@objc func timePickerValueChanged() { |
||||
linkExpiryTimeField.value = timePicker.date |
||||
} |
||||
|
||||
func configure(viewModel: SetTransferTicketsExpiryDateViewControllerViewModel) { |
||||
self.viewModel = viewModel |
||||
|
||||
view.backgroundColor = viewModel.backgroundColor |
||||
|
||||
header.configure(title: viewModel.headerTitle) |
||||
|
||||
ticketView.configure(viewModel: .init()) |
||||
|
||||
linkExpiryDateLabel.textAlignment = .center |
||||
linkExpiryDateLabel.textColor = viewModel.choiceLabelColor |
||||
linkExpiryDateLabel.font = viewModel.choiceLabelFont |
||||
linkExpiryDateLabel.text = viewModel.linkExpiryDateLabelText |
||||
|
||||
linkExpiryTimeLabel.textAlignment = .center |
||||
linkExpiryTimeLabel.textColor = viewModel.choiceLabelColor |
||||
linkExpiryTimeLabel.font = viewModel.choiceLabelFont |
||||
linkExpiryTimeLabel.text = viewModel.linkExpiryTimeLabelText |
||||
|
||||
ticketView.stateLabel.isHidden = true |
||||
|
||||
ticketView.ticketCountLabel.text = viewModel.ticketCount |
||||
|
||||
ticketView.titleLabel.text = viewModel.title |
||||
|
||||
ticketView.venueLabel.text = viewModel.venue |
||||
|
||||
ticketView.dateLabel.text = viewModel.date |
||||
|
||||
ticketView.seatRangeLabel.text = viewModel.seatRange |
||||
|
||||
ticketView.zoneNameLabel.text = viewModel.zoneName |
||||
|
||||
descriptionLabel.textAlignment = .center |
||||
descriptionLabel.numberOfLines = 0 |
||||
descriptionLabel.textColor = viewModel.descriptionLabelColor |
||||
descriptionLabel.font = viewModel.descriptionLabelFont |
||||
descriptionLabel.text = viewModel.descriptionLabelText |
||||
|
||||
noteTitleLabel.textAlignment = .center |
||||
noteTitleLabel.textColor = viewModel.noteTitleLabelColor |
||||
noteTitleLabel.font = viewModel.noteTitleLabelFont |
||||
noteTitleLabel.text = viewModel.noteTitleLabelText |
||||
|
||||
noteLabel.textAlignment = .center |
||||
noteLabel.numberOfLines = 0 |
||||
noteLabel.textColor = viewModel.noteLabelColor |
||||
noteLabel.font = viewModel.noteLabelFont |
||||
noteLabel.text = viewModel.noteLabelText |
||||
|
||||
noteBorderView.layer.cornerRadius = 20 |
||||
noteBorderView.layer.borderColor = viewModel.noteBorderColor.cgColor |
||||
noteBorderView.layer.borderWidth = 1 |
||||
|
||||
nextButton.setTitleColor(viewModel.buttonTitleColor, for: .normal) |
||||
nextButton.backgroundColor = viewModel.buttonBackgroundColor |
||||
nextButton.titleLabel?.font = viewModel.buttonFont |
||||
} |
||||
} |
||||
|
||||
extension SetTransferTicketsExpiryDateViewController: DateEntryFieldDelegate { |
||||
func didTap(in dateEntryField: DateEntryField) { |
||||
datePicker.isHidden = !datePicker.isHidden |
||||
if !datePicker.isHidden { |
||||
datePicker.date = linkExpiryDateField.value |
||||
timePicker.isHidden = true |
||||
} |
||||
} |
||||
} |
||||
|
||||
extension SetTransferTicketsExpiryDateViewController: TimeEntryFieldDelegate { |
||||
func didTap(in timeEntryField: TimeEntryField) { |
||||
timePicker.isHidden = !timePicker.isHidden |
||||
if !timePicker.isHidden { |
||||
timePicker.date = linkExpiryTimeField.value |
||||
datePicker.isHidden = true |
||||
} |
||||
} |
||||
} |
@ -1,159 +0,0 @@ |
||||
// Copyright © 2018 Stormbird PTE. LTD. |
||||
|
||||
import UIKit |
||||
import TrustKeystore |
||||
|
||||
protocol TransferTicketViaWalletAddressViewControllerDelegate: class { |
||||
func didChooseTransfer(to walletAddress: String, viewController: TransferTicketViaWalletAddressViewController) |
||||
} |
||||
|
||||
class TransferTicketViaWalletAddressViewController: UIViewController { |
||||
//roundedBackground is used to achieve the top 2 rounded corners-only effect since maskedCorners to not round bottom corners is not available in iOS 10 |
||||
let roundedBackground = UIView() |
||||
let titleLabel = UILabel() |
||||
let subtitleLabel = UILabel() |
||||
let textField = UITextField() |
||||
let ticketView = TicketRowView() |
||||
let actionButton = UIButton(type: .system) |
||||
var paymentFlow: PaymentFlow |
||||
weak var delegate: TransferTicketViaWalletAddressViewControllerDelegate? |
||||
let ticketHolder: TicketHolder |
||||
|
||||
init(ticketHolder: TicketHolder, paymentFlow: PaymentFlow) { |
||||
self.ticketHolder = ticketHolder |
||||
self.paymentFlow = paymentFlow |
||||
super.init(nibName: nil, bundle: nil) |
||||
|
||||
view.backgroundColor = Colors.appBackground |
||||
|
||||
roundedBackground.translatesAutoresizingMaskIntoConstraints = false |
||||
roundedBackground.cornerRadius = 20 |
||||
view.addSubview(roundedBackground) |
||||
|
||||
textField.translatesAutoresizingMaskIntoConstraints = false |
||||
textField.delegate = self |
||||
textField.returnKeyType = .done |
||||
|
||||
actionButton.translatesAutoresizingMaskIntoConstraints = false |
||||
actionButton.addTarget(self, action: #selector(transfer), for: .touchUpInside) |
||||
roundedBackground.addSubview(actionButton) |
||||
|
||||
ticketView.translatesAutoresizingMaskIntoConstraints = false |
||||
view.addSubview(ticketView) |
||||
|
||||
let stackView = UIStackView(arrangedSubviews: [ |
||||
.spacer(height: 7), |
||||
titleLabel, |
||||
.spacer(height: 20), |
||||
subtitleLabel, |
||||
.spacer(height: 10), |
||||
textField, |
||||
.spacer(height: 40), |
||||
ticketView, |
||||
]) |
||||
stackView.translatesAutoresizingMaskIntoConstraints = false |
||||
stackView.axis = .vertical |
||||
stackView.spacing = 0 |
||||
stackView.distribution = .fill |
||||
stackView.alignment = .center |
||||
roundedBackground.addSubview(stackView) |
||||
|
||||
let marginToHideBottomRoundedCorners = CGFloat(30) |
||||
NSLayoutConstraint.activate([ |
||||
textField.leadingAnchor.constraint(equalTo: roundedBackground.leadingAnchor, constant: 30), |
||||
textField.trailingAnchor.constraint(equalTo: roundedBackground.trailingAnchor, constant: -30), |
||||
textField.heightAnchor.constraint(equalToConstant: 50), |
||||
|
||||
ticketView.leadingAnchor.constraint(equalTo: view.leadingAnchor), |
||||
ticketView.trailingAnchor.constraint(equalTo: view.trailingAnchor), |
||||
|
||||
stackView.leadingAnchor.constraint(equalTo: roundedBackground.leadingAnchor), |
||||
stackView.trailingAnchor.constraint(equalTo: roundedBackground.trailingAnchor), |
||||
stackView.topAnchor.constraint(equalTo: roundedBackground.topAnchor, constant: 16), |
||||
|
||||
actionButton.leadingAnchor.constraint(equalTo: roundedBackground.leadingAnchor), |
||||
actionButton.trailingAnchor.constraint(equalTo: roundedBackground.trailingAnchor), |
||||
actionButton.heightAnchor.constraint(equalToConstant: 60), |
||||
actionButton.bottomAnchor.constraint(equalTo: roundedBackground.bottomAnchor, constant: -marginToHideBottomRoundedCorners), |
||||
|
||||
roundedBackground.leadingAnchor.constraint(equalTo: view.leadingAnchor), |
||||
roundedBackground.trailingAnchor.constraint(equalTo: view.trailingAnchor), |
||||
roundedBackground.topAnchor.constraint(equalTo: view.topAnchor), |
||||
roundedBackground.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: marginToHideBottomRoundedCorners), |
||||
]) |
||||
} |
||||
|
||||
required init?(coder aDecoder: NSCoder) { |
||||
fatalError("init(coder:) has not been implemented") |
||||
} |
||||
|
||||
func configure(viewModel: TransferTicketViaWalletAddressViewControllerViewModel) { |
||||
roundedBackground.backgroundColor = viewModel.contentsBackgroundColor |
||||
roundedBackground.layer.cornerRadius = 20 |
||||
|
||||
titleLabel.numberOfLines = 0 |
||||
titleLabel.textColor = viewModel.titleColor |
||||
titleLabel.font = viewModel.titleFont |
||||
titleLabel.textAlignment = .center |
||||
titleLabel.text = viewModel.titleLabelText |
||||
|
||||
subtitleLabel.textColor = viewModel.subtitleColor |
||||
subtitleLabel.font = viewModel.subtitleFont |
||||
subtitleLabel.textAlignment = .center |
||||
subtitleLabel.text = viewModel.subtitleLabelText |
||||
|
||||
textField.textColor = viewModel.textFieldTextColor |
||||
textField.font = viewModel.textFieldFont |
||||
textField.layer.borderColor = viewModel.textFieldBorderColor.cgColor |
||||
textField.layer.borderWidth = viewModel.textFieldBorderWidth |
||||
textField.leftView = .spacerWidth(viewModel.textFieldHorizontalPadding) |
||||
textField.leftViewMode = .always |
||||
textField.rightView = .spacerWidth(viewModel.textFieldHorizontalPadding) |
||||
textField.rightViewMode = .always |
||||
|
||||
ticketView.configure(viewModel: .init()) |
||||
|
||||
ticketView.stateLabel.isHidden = true |
||||
|
||||
ticketView.ticketCountLabel.text = viewModel.ticketCount |
||||
|
||||
ticketView.titleLabel.text = viewModel.title |
||||
|
||||
ticketView.venueLabel.text = viewModel.venue |
||||
|
||||
ticketView.dateLabel.text = viewModel.date |
||||
|
||||
ticketView.seatRangeLabel.text = viewModel.seatRange |
||||
|
||||
ticketView.zoneNameLabel.text = viewModel.zoneName |
||||
|
||||
actionButton.setTitle(viewModel.actionButtonTitle, for: .normal) |
||||
actionButton.setTitleColor(viewModel.actionButtonTitleColor, for: .normal) |
||||
actionButton.setBackgroundColor(viewModel.actionButtonBackgroundColor, forState: .normal) |
||||
actionButton.titleLabel?.font = viewModel.actionButtonTitleFont |
||||
} |
||||
|
||||
override func viewDidLayoutSubviews() { |
||||
super.viewDidLayoutSubviews() |
||||
actionButton.layer.cornerRadius = actionButton.frame.size.height / 2 |
||||
textField.layer.cornerRadius = textField.frame.size.height / 2 |
||||
} |
||||
|
||||
@objc func transfer() { |
||||
if let address = textField.text, !address.isEmpty { |
||||
guard let _ = Address(string: address) else { |
||||
displayError(error: Errors.invalidAddress) |
||||
return |
||||
} |
||||
|
||||
delegate?.didChooseTransfer(to: address, viewController: self) |
||||
} |
||||
} |
||||
} |
||||
|
||||
extension TransferTicketViaWalletAddressViewController: UITextFieldDelegate { |
||||
func textFieldShouldReturn(_ textField: UITextField) -> Bool { |
||||
textField.resignFirstResponder() |
||||
return true |
||||
} |
||||
} |
@ -0,0 +1,185 @@ |
||||
// Copyright © 2018 Stormbird PTE. LTD. |
||||
|
||||
import UIKit |
||||
|
||||
protocol TransferTicketsChooseTransferModeViewControllerDelegate: class { |
||||
func didSelectQuantity(ticketHolder: TicketHolder, in viewController: TransferTicketsChooseTransferModeViewController) |
||||
func didPressViewInfo(in viewController: TransferTicketsChooseTransferModeViewController) |
||||
} |
||||
|
||||
class TransferTicketsChooseTransferModeViewController: UIViewController { |
||||
|
||||
//roundedBackground is used to achieve the top 2 rounded corners-only effect since maskedCorners to not round bottom corners is not available in iOS 10 |
||||
let roundedBackground = UIView() |
||||
let header = TicketsViewControllerTitleHeader() |
||||
let subtitleLabel = UILabel() |
||||
var quantityStepper = NumberStepper() |
||||
let ticketView = TicketRowView() |
||||
let nextButton = UIButton(type: .system) |
||||
var viewModel: TransferTicketsChooseTransferModeViewControllerViewModel! |
||||
var paymentFlow: PaymentFlow |
||||
weak var delegate: TransferTicketsChooseTransferModeViewControllerDelegate? |
||||
|
||||
init(paymentFlow: PaymentFlow) { |
||||
self.paymentFlow = paymentFlow |
||||
super.init(nibName: nil, bundle: nil) |
||||
|
||||
navigationItem.rightBarButtonItem = UIBarButtonItem(image: R.image.location(), style: .plain, target: self, action: #selector(showInfo)) |
||||
|
||||
roundedBackground.translatesAutoresizingMaskIntoConstraints = false |
||||
roundedBackground.backgroundColor = Colors.appWhite |
||||
roundedBackground.cornerRadius = 20 |
||||
view.addSubview(roundedBackground) |
||||
|
||||
subtitleLabel.translatesAutoresizingMaskIntoConstraints = false |
||||
|
||||
nextButton.setTitle(R.string.localizable.aWalletNextButtonTitle(), for: .normal) |
||||
nextButton.addTarget(self, action: #selector(nextButtonTapped), for: .touchUpInside) |
||||
|
||||
ticketView.translatesAutoresizingMaskIntoConstraints = false |
||||
view.addSubview(ticketView) |
||||
|
||||
quantityStepper.translatesAutoresizingMaskIntoConstraints = false |
||||
quantityStepper.minimumValue = 1 |
||||
quantityStepper.value = 1 |
||||
view.addSubview(quantityStepper) |
||||
|
||||
let stackView = UIStackView(arrangedSubviews: [ |
||||
header, |
||||
ticketView, |
||||
.spacer(height: 20), |
||||
subtitleLabel, |
||||
.spacer(height: 4), |
||||
quantityStepper, |
||||
]) |
||||
stackView.translatesAutoresizingMaskIntoConstraints = false |
||||
stackView.axis = .vertical |
||||
stackView.spacing = 0 |
||||
stackView.distribution = .fill |
||||
stackView.alignment = .center |
||||
roundedBackground.addSubview(stackView) |
||||
|
||||
let buttonsStackView = UIStackView(arrangedSubviews: [nextButton]) |
||||
buttonsStackView.translatesAutoresizingMaskIntoConstraints = false |
||||
buttonsStackView.axis = .horizontal |
||||
buttonsStackView.spacing = 0 |
||||
buttonsStackView.distribution = .fillEqually |
||||
buttonsStackView.setContentHuggingPriority(.required, for: .horizontal) |
||||
|
||||
let marginToHideBottomRoundedCorners = CGFloat(30) |
||||
let footerBar = UIView() |
||||
footerBar.translatesAutoresizingMaskIntoConstraints = false |
||||
footerBar.backgroundColor = Colors.appHighlightGreen |
||||
roundedBackground.addSubview(footerBar) |
||||
|
||||
let buttonsHeight = CGFloat(60) |
||||
footerBar.addSubview(buttonsStackView) |
||||
|
||||
NSLayoutConstraint.activate([ |
||||
header.heightAnchor.constraint(equalToConstant: 90), |
||||
|
||||
quantityStepper.heightAnchor.constraint(equalToConstant: 50), |
||||
|
||||
ticketView.leadingAnchor.constraint(equalTo: view.leadingAnchor), |
||||
ticketView.trailingAnchor.constraint(equalTo: view.trailingAnchor), |
||||
|
||||
roundedBackground.leadingAnchor.constraint(equalTo: view.leadingAnchor), |
||||
roundedBackground.trailingAnchor.constraint(equalTo: view.trailingAnchor), |
||||
roundedBackground.topAnchor.constraint(equalTo: view.topAnchor), |
||||
roundedBackground.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: marginToHideBottomRoundedCorners), |
||||
|
||||
stackView.leadingAnchor.constraint(equalTo: roundedBackground.leadingAnchor), |
||||
stackView.trailingAnchor.constraint(equalTo: roundedBackground.trailingAnchor), |
||||
stackView.topAnchor.constraint(equalTo: roundedBackground.topAnchor), |
||||
|
||||
buttonsStackView.leadingAnchor.constraint(equalTo: footerBar.leadingAnchor), |
||||
buttonsStackView.trailingAnchor.constraint(equalTo: footerBar.trailingAnchor), |
||||
buttonsStackView.topAnchor.constraint(equalTo: footerBar.topAnchor), |
||||
buttonsStackView.heightAnchor.constraint(equalToConstant: buttonsHeight), |
||||
|
||||
footerBar.leadingAnchor.constraint(equalTo: view.leadingAnchor), |
||||
footerBar.trailingAnchor.constraint(equalTo: view.trailingAnchor), |
||||
footerBar.heightAnchor.constraint(equalToConstant: buttonsHeight), |
||||
footerBar.bottomAnchor.constraint(equalTo: view.bottomAnchor), |
||||
]) |
||||
} |
||||
|
||||
required init?(coder aDecoder: NSCoder) { |
||||
fatalError("init(coder:) has not been implemented") |
||||
} |
||||
|
||||
@objc |
||||
func nextButtonTapped() { |
||||
if quantityStepper.value == 0 { |
||||
UIAlertController.alert(title: "", |
||||
message: R.string.localizable.aWalletTicketTokenTransferSelectTicketQuantityAtLeastOneTitle(), |
||||
alertButtonTitles: [R.string.localizable.oK()], |
||||
alertButtonStyles: [.cancel], |
||||
viewController: self, |
||||
completion: nil) |
||||
} else { |
||||
delegate?.didSelectQuantity(ticketHolder: getTicketHolderFromQuantity(), in: self) |
||||
} |
||||
} |
||||
|
||||
@objc func showInfo() { |
||||
delegate?.didPressViewInfo(in: self) |
||||
} |
||||
|
||||
func configure(viewModel: TransferTicketsChooseTransferModeViewControllerViewModel) { |
||||
self.viewModel = viewModel |
||||
|
||||
view.backgroundColor = viewModel.backgroundColor |
||||
|
||||
header.configure(title: viewModel.headerTitle) |
||||
|
||||
subtitleLabel.textAlignment = .center |
||||
subtitleLabel.textColor = viewModel.subtitleColor |
||||
subtitleLabel.font = viewModel.subtitleFont |
||||
subtitleLabel.text = viewModel.subtitleText |
||||
|
||||
ticketView.configure(viewModel: .init()) |
||||
|
||||
quantityStepper.borderWidth = 2 |
||||
quantityStepper.clipsToBounds = true |
||||
quantityStepper.borderColor = viewModel.stepperBorderColor |
||||
quantityStepper.maximumValue = viewModel.maxValue |
||||
|
||||
ticketView.stateLabel.isHidden = true |
||||
|
||||
ticketView.ticketCountLabel.text = viewModel.ticketCount |
||||
|
||||
ticketView.titleLabel.text = viewModel.title |
||||
|
||||
ticketView.venueLabel.text = viewModel.venue |
||||
|
||||
ticketView.dateLabel.text = viewModel.date |
||||
|
||||
ticketView.seatRangeLabel.text = viewModel.seatRange |
||||
|
||||
ticketView.zoneNameLabel.text = viewModel.zoneName |
||||
|
||||
nextButton.setTitleColor(viewModel.buttonTitleColor, for: .normal) |
||||
nextButton.backgroundColor = viewModel.buttonBackgroundColor |
||||
nextButton.titleLabel?.font = viewModel.buttonFont |
||||
} |
||||
|
||||
private func getTicketHolderFromQuantity() -> TicketHolder { |
||||
let quantity = quantityStepper.value |
||||
let ticketHolder = viewModel.ticketHolder |
||||
let tickets = Array(ticketHolder.tickets[..<quantity]) |
||||
return TicketHolder( |
||||
tickets: tickets, |
||||
zone: ticketHolder.zone, |
||||
name: ticketHolder.name, |
||||
venue: ticketHolder.venue, |
||||
date: ticketHolder.date, |
||||
status: ticketHolder.status |
||||
) |
||||
} |
||||
|
||||
override func viewDidLayoutSubviews() { |
||||
super.viewDidLayoutSubviews() |
||||
quantityStepper.layer.cornerRadius = quantityStepper.frame.size.height / 2 |
||||
} |
||||
} |
@ -0,0 +1,242 @@ |
||||
// Copyright © 2018 Stormbird PTE. LTD. |
||||
|
||||
import UIKit |
||||
import QRCodeReaderViewController |
||||
|
||||
protocol TransferTicketsViaWalletAddressViewControllerDelegate: class { |
||||
func didEnterWalletAddress(ticketHolder: TicketHolder, to walletAddress: String, paymentFlow: PaymentFlow, in viewController: TransferTicketsViaWalletAddressViewController) |
||||
func didPressViewInfo(in viewController: TransferTicketsViaWalletAddressViewController) |
||||
} |
||||
|
||||
class TransferTicketsViaWalletAddressViewController: UIViewController { |
||||
|
||||
//roundedBackground is used to achieve the top 2 rounded corners-only effect since maskedCorners to not round bottom corners is not available in iOS 10 |
||||
let roundedBackground = UIView() |
||||
let header = TicketsViewControllerTitleHeader() |
||||
let ticketView = TicketRowView() |
||||
let targetAddressLabel = UILabel() |
||||
let targetAddressTextField = UITextField() |
||||
let nextButton = UIButton(type: .system) |
||||
var viewModel: TransferTicketsViaWalletAddressViewControllerViewModel! |
||||
var ticketHolder: TicketHolder |
||||
var paymentFlow: PaymentFlow |
||||
weak var delegate: TransferTicketsViaWalletAddressViewControllerDelegate? |
||||
|
||||
init(ticketHolder: TicketHolder, paymentFlow: PaymentFlow) { |
||||
self.ticketHolder = ticketHolder |
||||
self.paymentFlow = paymentFlow |
||||
super.init(nibName: nil, bundle: nil) |
||||
|
||||
navigationItem.rightBarButtonItem = UIBarButtonItem(image: R.image.location(), style: .plain, target: self, action: #selector(showInfo)) |
||||
|
||||
roundedBackground.translatesAutoresizingMaskIntoConstraints = false |
||||
roundedBackground.backgroundColor = Colors.appWhite |
||||
roundedBackground.cornerRadius = 20 |
||||
view.addSubview(roundedBackground) |
||||
|
||||
targetAddressTextField.translatesAutoresizingMaskIntoConstraints = false |
||||
targetAddressTextField.delegate = self |
||||
targetAddressTextField.returnKeyType = .done |
||||
targetAddressTextField.leftViewMode = .always |
||||
targetAddressTextField.rightViewMode = .always |
||||
|
||||
nextButton.setTitle(R.string.localizable.aWalletNextButtonTitle(), for: .normal) |
||||
nextButton.addTarget(self, action: #selector(nextButtonTapped), for: .touchUpInside) |
||||
|
||||
ticketView.translatesAutoresizingMaskIntoConstraints = false |
||||
view.addSubview(ticketView) |
||||
|
||||
let stackView = UIStackView(arrangedSubviews: [ |
||||
header, |
||||
ticketView, |
||||
.spacer(height: 10), |
||||
targetAddressLabel, |
||||
.spacer(height: ScreenChecker().isNarrowScreen() ? 2 : 4), |
||||
targetAddressTextField, |
||||
]) |
||||
stackView.translatesAutoresizingMaskIntoConstraints = false |
||||
stackView.axis = .vertical |
||||
stackView.spacing = 0 |
||||
stackView.distribution = .fill |
||||
stackView.alignment = .center |
||||
roundedBackground.addSubview(stackView) |
||||
|
||||
let buttonsStackView = UIStackView(arrangedSubviews: [nextButton]) |
||||
buttonsStackView.translatesAutoresizingMaskIntoConstraints = false |
||||
buttonsStackView.axis = .horizontal |
||||
buttonsStackView.spacing = 0 |
||||
buttonsStackView.distribution = .fillEqually |
||||
buttonsStackView.setContentHuggingPriority(.required, for: .horizontal) |
||||
|
||||
let marginToHideBottomRoundedCorners = CGFloat(30) |
||||
let footerBar = UIView() |
||||
footerBar.translatesAutoresizingMaskIntoConstraints = false |
||||
footerBar.backgroundColor = Colors.appHighlightGreen |
||||
roundedBackground.addSubview(footerBar) |
||||
|
||||
let buttonsHeight = CGFloat(60) |
||||
footerBar.addSubview(buttonsStackView) |
||||
|
||||
NSLayoutConstraint.activate([ |
||||
header.heightAnchor.constraint(equalToConstant: 90), |
||||
|
||||
ticketView.leadingAnchor.constraint(equalTo: view.leadingAnchor), |
||||
ticketView.trailingAnchor.constraint(equalTo: view.trailingAnchor), |
||||
|
||||
targetAddressTextField.leadingAnchor.constraint(equalTo: roundedBackground.leadingAnchor, constant: 30), |
||||
targetAddressTextField.trailingAnchor.constraint(equalTo: roundedBackground.trailingAnchor, constant: -30), |
||||
targetAddressTextField.heightAnchor.constraint(equalToConstant: ScreenChecker().isNarrowScreen() ? 30 : 50), |
||||
|
||||
roundedBackground.leadingAnchor.constraint(equalTo: view.leadingAnchor), |
||||
roundedBackground.trailingAnchor.constraint(equalTo: view.trailingAnchor), |
||||
roundedBackground.topAnchor.constraint(equalTo: view.topAnchor), |
||||
roundedBackground.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: marginToHideBottomRoundedCorners), |
||||
|
||||
stackView.leadingAnchor.constraint(equalTo: roundedBackground.leadingAnchor), |
||||
stackView.trailingAnchor.constraint(equalTo: roundedBackground.trailingAnchor), |
||||
stackView.topAnchor.constraint(equalTo: roundedBackground.topAnchor), |
||||
|
||||
buttonsStackView.leadingAnchor.constraint(equalTo: footerBar.leadingAnchor), |
||||
buttonsStackView.trailingAnchor.constraint(equalTo: footerBar.trailingAnchor), |
||||
buttonsStackView.topAnchor.constraint(equalTo: footerBar.topAnchor), |
||||
buttonsStackView.heightAnchor.constraint(equalToConstant: buttonsHeight), |
||||
|
||||
footerBar.leadingAnchor.constraint(equalTo: view.leadingAnchor), |
||||
footerBar.trailingAnchor.constraint(equalTo: view.trailingAnchor), |
||||
footerBar.heightAnchor.constraint(equalToConstant: buttonsHeight), |
||||
footerBar.bottomAnchor.constraint(equalTo: view.bottomAnchor), |
||||
]) |
||||
} |
||||
|
||||
required init?(coder aDecoder: NSCoder) { |
||||
fatalError("init(coder:) has not been implemented") |
||||
} |
||||
|
||||
@objc func nextButtonTapped() { |
||||
let address = targetAddressTextField.text?.trimmed ?? "" |
||||
delegate?.didEnterWalletAddress(ticketHolder: ticketHolder, to: address, paymentFlow: paymentFlow, in: self) |
||||
} |
||||
|
||||
@objc func showInfo() { |
||||
delegate?.didPressViewInfo(in: self) |
||||
} |
||||
|
||||
func configure(viewModel: TransferTicketsViaWalletAddressViewControllerViewModel) { |
||||
let firstConfigure = self.viewModel == nil |
||||
self.viewModel = viewModel |
||||
|
||||
if firstConfigure { |
||||
targetAddressTextField.leftView = .spacerWidth(viewModel.textFieldHorizontalPadding) |
||||
targetAddressTextField.rightView = makeTargetAddressRightView() |
||||
} |
||||
|
||||
view.backgroundColor = viewModel.backgroundColor |
||||
|
||||
header.configure(title: viewModel.headerTitle) |
||||
|
||||
ticketView.configure(viewModel: .init()) |
||||
|
||||
ticketView.stateLabel.isHidden = true |
||||
|
||||
ticketView.ticketCountLabel.text = viewModel.ticketCount |
||||
|
||||
ticketView.titleLabel.text = viewModel.title |
||||
|
||||
ticketView.venueLabel.text = viewModel.venue |
||||
|
||||
ticketView.dateLabel.text = viewModel.date |
||||
|
||||
ticketView.seatRangeLabel.text = viewModel.seatRange |
||||
|
||||
ticketView.zoneNameLabel.text = viewModel.zoneName |
||||
|
||||
targetAddressTextField.textColor = viewModel.textFieldTextColor |
||||
targetAddressTextField.font = viewModel.textFieldFont |
||||
targetAddressTextField.layer.borderColor = viewModel.textFieldBorderColor.cgColor |
||||
targetAddressTextField.layer.borderWidth = viewModel.textFieldBorderWidth |
||||
|
||||
targetAddressLabel.text = R.string.localizable.aSendRecipientAddressTitle() |
||||
targetAddressLabel.font = viewModel.textFieldsLabelFont |
||||
targetAddressLabel.textColor = viewModel.textFieldsLabelTextColor |
||||
|
||||
nextButton.setTitleColor(viewModel.buttonTitleColor, for: .normal) |
||||
nextButton.backgroundColor = viewModel.buttonBackgroundColor |
||||
nextButton.titleLabel?.font = viewModel.buttonFont |
||||
} |
||||
|
||||
override func viewDidLayoutSubviews() { |
||||
super.viewDidLayoutSubviews() |
||||
roundCornersBasedOnHeight() |
||||
} |
||||
|
||||
private func roundCornersBasedOnHeight() { |
||||
targetAddressTextField.layer.cornerRadius = targetAddressTextField.frame.size.height / 2 |
||||
} |
||||
|
||||
@objc func openReader() { |
||||
let controller = QRCodeReaderViewController() |
||||
controller.delegate = self |
||||
present(controller, animated: true, completion: nil) |
||||
} |
||||
|
||||
@objc func pasteAction() { |
||||
guard let value = UIPasteboard.general.string?.trimmed else { |
||||
return displayError(error: SendInputErrors.emptyClipBoard) |
||||
} |
||||
|
||||
guard CryptoAddressValidator.isValidAddress(value) else { |
||||
return displayError(error: Errors.invalidAddress) |
||||
} |
||||
targetAddressTextField.text = value |
||||
} |
||||
|
||||
private func makeTargetAddressRightView() -> UIView { |
||||
let pasteButton = Button(size: .normal, style: .borderless) |
||||
pasteButton.translatesAutoresizingMaskIntoConstraints = false |
||||
pasteButton.setTitle(R.string.localizable.sendPasteButtonTitle(), for: .normal) |
||||
pasteButton.titleLabel?.font = Fonts.regular(size: 14)! |
||||
pasteButton.setTitleColor(UIColor(red: 155, green: 155, blue: 155), for: .normal) |
||||
pasteButton.addTarget(self, action: #selector(pasteAction), for: .touchUpInside) |
||||
|
||||
let scanQRCodeButton = Button(size: .normal, style: .borderless) |
||||
scanQRCodeButton.translatesAutoresizingMaskIntoConstraints = false |
||||
scanQRCodeButton.setImage(R.image.qr_code_icon(), for: .normal) |
||||
scanQRCodeButton.setTitleColor(UIColor(red: 155, green: 155, blue: 155), for: .normal) |
||||
scanQRCodeButton.addTarget(self, action: #selector(openReader), for: .touchUpInside) |
||||
|
||||
let targetAddressRightView = UIStackView(arrangedSubviews: [ |
||||
pasteButton, |
||||
scanQRCodeButton, |
||||
]) |
||||
targetAddressRightView.translatesAutoresizingMaskIntoConstraints = false |
||||
targetAddressRightView.distribution = .equalSpacing |
||||
targetAddressRightView.spacing = 0 |
||||
targetAddressRightView.axis = .horizontal |
||||
|
||||
return targetAddressRightView |
||||
} |
||||
} |
||||
|
||||
extension TransferTicketsViaWalletAddressViewController: QRCodeReaderDelegate { |
||||
func readerDidCancel(_ reader: QRCodeReaderViewController!) { |
||||
reader.stopScanning() |
||||
reader.dismiss(animated: true, completion: nil) |
||||
} |
||||
|
||||
func reader(_ reader: QRCodeReaderViewController!, didScanResult result: String!) { |
||||
reader.stopScanning() |
||||
reader.dismiss(animated: true) |
||||
|
||||
guard let result = QRURLParser.from(string: result) else { |
||||
return |
||||
} |
||||
targetAddressTextField.text = result.address |
||||
} |
||||
} |
||||
|
||||
extension TransferTicketsViaWalletAddressViewController: UITextFieldDelegate { |
||||
func textFieldShouldReturn(_ textField: UITextField) -> Bool { |
||||
view.endEditing(true) |
||||
return true |
||||
} |
||||
} |
@ -1,58 +1,58 @@ |
||||
// Copyright © 2018 Stormbird PTE. LTD. |
||||
|
||||
import Foundation |
||||
import UIKit |
||||
|
||||
class ChooseTicketTransferModeViewControllerViewModel { |
||||
var contentsBackgroundColor: UIColor { |
||||
return Colors.appWhite |
||||
} |
||||
var titleColor: UIColor { |
||||
return Colors.appText |
||||
} |
||||
var titleFont: UIFont { |
||||
return Fonts.light(size: 25)! |
||||
} |
||||
var titleLabelText: String { |
||||
return R.string.localizable.aWalletTicketTokenTransferModeChooseTitle() |
||||
} |
||||
var textButtonTitle: String { |
||||
return R.string.localizable.aWalletTicketTokenTransferModeChooseTextTitle() |
||||
} |
||||
var textButtonImage: UIImage? { |
||||
return R.image.transfer_text() |
||||
struct ChooseTicketTransferModeViewControllerViewModel { |
||||
|
||||
var ticketHolder: TicketHolder |
||||
|
||||
var headerTitle: String { |
||||
return R.string.localizable.aWalletTicketTokenTransferSelectQuantityTitle() |
||||
} |
||||
var emailButtonTitle: String { |
||||
return R.string.localizable.aWalletTicketTokenTransferModeChooseEmailTitle() |
||||
|
||||
var backgroundColor: UIColor { |
||||
return Colors.appBackground |
||||
} |
||||
var emailButtonImage: UIImage? { |
||||
return R.image.transfer_email() |
||||
|
||||
var buttonTitleColor: UIColor { |
||||
return Colors.appWhite |
||||
} |
||||
var inputWalletAddressButtonTitle: String { |
||||
return R.string.localizable.aWalletTicketTokenTransferModeChooseInputWalletAddressTitle() |
||||
|
||||
var buttonBackgroundColor: UIColor { |
||||
return Colors.appHighlightGreen |
||||
} |
||||
var inputWalletAddressButtonImage: UIImage? { |
||||
return R.image.transfer_wallet_address() |
||||
|
||||
var buttonFont: UIFont { |
||||
if ScreenChecker().isNarrowScreen() { |
||||
return Fonts.regular(size: 13)! |
||||
} else { |
||||
return Fonts.regular(size: 16)! |
||||
} |
||||
} |
||||
var qrCodeScannerButtonTitle: String { |
||||
return R.string.localizable.aWalletTicketTokenTransferModeChooseWalletAddressViaQRCodeScannerTitle() |
||||
|
||||
var ticketCount: String { |
||||
return "x\(ticketHolder.tickets.count)" |
||||
} |
||||
var qrCodeScannerButtonImage: UIImage? { |
||||
return R.image.transfer_qr_code() |
||||
|
||||
var title: String { |
||||
return ticketHolder.name |
||||
} |
||||
var otherButtonTitle: String { |
||||
return R.string.localizable.aWalletTicketTokenTransferModeChooseOtherTitle() |
||||
|
||||
var seatRange: String { |
||||
return ticketHolder.seatRange |
||||
} |
||||
var otherButtonImage: UIImage? { |
||||
return R.image.transfer_others() |
||||
|
||||
var zoneName: String { |
||||
return ticketHolder.zone |
||||
} |
||||
var buttonTitleFont: UIFont { |
||||
if ScreenChecker().isNarrowScreen() { |
||||
return Fonts.light(size: 18)! |
||||
} else { |
||||
return Fonts.light(size: 21)! |
||||
} |
||||
|
||||
var venue: String { |
||||
return ticketHolder.venue |
||||
} |
||||
var buttonTitleColor: UIColor { |
||||
return Colors.appText |
||||
|
||||
var date: String { |
||||
//TODO Should format be localized? |
||||
return ticketHolder.date.format("dd MMM yyyy") |
||||
} |
||||
} |
||||
|
@ -0,0 +1,110 @@ |
||||
// Copyright © 2018 Stormbird PTE. LTD. |
||||
|
||||
import Foundation |
||||
import UIKit |
||||
|
||||
struct SetTransferTicketsExpiryDateViewControllerViewModel { |
||||
|
||||
var ticketHolder: TicketHolder |
||||
|
||||
var headerTitle: String { |
||||
return R.string.localizable.aWalletTicketTokenTransferSelectQuantityTitle() |
||||
} |
||||
|
||||
var backgroundColor: UIColor { |
||||
return Colors.appBackground |
||||
} |
||||
|
||||
var buttonTitleColor: UIColor { |
||||
return Colors.appWhite |
||||
} |
||||
|
||||
var buttonBackgroundColor: UIColor { |
||||
return Colors.appHighlightGreen |
||||
} |
||||
|
||||
var buttonFont: UIFont { |
||||
return Fonts.regular(size: 20)! |
||||
} |
||||
|
||||
var ticketCount: String { |
||||
return "x\(ticketHolder.tickets.count)" |
||||
} |
||||
|
||||
var title: String { |
||||
return ticketHolder.name |
||||
} |
||||
|
||||
var seatRange: String { |
||||
return ticketHolder.seatRange |
||||
} |
||||
|
||||
var zoneName: String { |
||||
return ticketHolder.zone |
||||
} |
||||
|
||||
var venue: String { |
||||
return ticketHolder.venue |
||||
} |
||||
|
||||
var date: String { |
||||
//TODO Should format be localized? |
||||
return ticketHolder.date.format("dd MMM yyyy") |
||||
} |
||||
|
||||
var descriptionLabelText: String { |
||||
return R.string.localizable.aWalletTicketTokenSellMagicLinkDescriptionTitle() |
||||
} |
||||
|
||||
var descriptionLabelFont: UIFont { |
||||
return Fonts.light(size: 21)! |
||||
} |
||||
|
||||
var descriptionLabelColor: UIColor { |
||||
return Colors.appText |
||||
} |
||||
|
||||
var noteTitleLabelText: String { |
||||
return R.string.localizable.aWalletTicketTokenSellNoteTitleLabelTitle() |
||||
} |
||||
|
||||
var noteTitleLabelFont: UIFont { |
||||
return Fonts.semibold(size: 21)! |
||||
} |
||||
|
||||
var noteTitleLabelColor: UIColor { |
||||
return Colors.appRed |
||||
} |
||||
|
||||
var noteLabelText: String { |
||||
return R.string.localizable.aWalletTicketTokenSellNoteLabelTitle() |
||||
} |
||||
|
||||
var noteLabelFont: UIFont { |
||||
return Fonts.light(size: 21)! |
||||
} |
||||
|
||||
var noteLabelColor: UIColor { |
||||
return Colors.appRed |
||||
} |
||||
|
||||
var noteBorderColor: UIColor { |
||||
return Colors.appRed |
||||
} |
||||
|
||||
var choiceLabelColor: UIColor { |
||||
return UIColor(red: 155, green: 155, blue: 155) |
||||
} |
||||
|
||||
var choiceLabelFont: UIFont { |
||||
return Fonts.regular(size: 10)! |
||||
} |
||||
|
||||
var linkExpiryDateLabelText: String { |
||||
return R.string.localizable.aWalletTicketTokenSellLinkExpiryDateTitle() |
||||
} |
||||
|
||||
var linkExpiryTimeLabelText: String { |
||||
return R.string.localizable.aWalletTicketTokenSellLinkExpiryTimeTitle() |
||||
} |
||||
} |
@ -0,0 +1,74 @@ |
||||
// Copyright © 2018 Stormbird PTE. LTD. |
||||
|
||||
import Foundation |
||||
import UIKit |
||||
|
||||
struct TransferTicketsChooseTransferModeViewControllerViewModel { |
||||
|
||||
var ticketHolder: TicketHolder |
||||
|
||||
var headerTitle: String { |
||||
return R.string.localizable.aWalletTicketTokenTransferSelectQuantityTitle() |
||||
} |
||||
|
||||
var maxValue: Int { |
||||
return ticketHolder.tickets.count |
||||
} |
||||
|
||||
var backgroundColor: UIColor { |
||||
return Colors.appBackground |
||||
} |
||||
|
||||
var buttonTitleColor: UIColor { |
||||
return Colors.appWhite |
||||
} |
||||
|
||||
var buttonBackgroundColor: UIColor { |
||||
return Colors.appHighlightGreen |
||||
} |
||||
|
||||
var buttonFont: UIFont { |
||||
return Fonts.regular(size: 20)! |
||||
} |
||||
|
||||
var subtitleColor: UIColor { |
||||
return UIColor(red: 155, green: 155, blue: 155) |
||||
} |
||||
|
||||
var subtitleFont: UIFont { |
||||
return Fonts.regular(size: 10)! |
||||
} |
||||
|
||||
var stepperBorderColor: UIColor { |
||||
return Colors.appBackground |
||||
} |
||||
|
||||
var ticketCount: String { |
||||
return "x\(ticketHolder.tickets.count)" |
||||
} |
||||
|
||||
var title: String { |
||||
return ticketHolder.name |
||||
} |
||||
|
||||
var seatRange: String { |
||||
return ticketHolder.seatRange |
||||
} |
||||
|
||||
var zoneName: String { |
||||
return ticketHolder.zone |
||||
} |
||||
|
||||
var venue: String { |
||||
return ticketHolder.venue |
||||
} |
||||
|
||||
var subtitleText: String { |
||||
return R.string.localizable.aWalletTicketTokenTransferQuantityTitle() |
||||
} |
||||
|
||||
var date: String { |
||||
//TODO Should format be localized? |
||||
return ticketHolder.date.format("dd MMM yyyy") |
||||
} |
||||
} |
Loading…
Reference in new issue