Skip to content

Commit

Permalink
feat(GiniHealthSDK): Landscape PaymentReview CollectionView + Image +…
Browse files Browse the repository at this point in the history
… PaymentReviewContainer

IPC-478
  • Loading branch information
razvancapra committed Feb 6, 2025
1 parent 3ee7be5 commit 302ee68
Show file tree
Hide file tree
Showing 3 changed files with 194 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ public final class PaymentReviewViewController: BottomSheetViewController, UIGes
lazy var paymentInfoContainerView = buildPaymentInfoContainerView()
lazy var collectionView = buildCollectionView()
lazy var pageControl = buildPageControl()

private var portraitConstraints: [NSLayoutConstraint] = []
private var landscapeConstraints: [NSLayoutConstraint] = []

private var infoBarBottomConstraint: NSLayoutConstraint?

Expand Down Expand Up @@ -156,6 +159,7 @@ public final class PaymentReviewViewController: BottomSheetViewController, UIGes
layoutInfoBar()
setContent(content: paymentInfoContainerView)
}
setupInitialLayout()
}

// MARK: - Pay Button Action
Expand Down Expand Up @@ -398,7 +402,6 @@ fileprivate extension PaymentReviewViewController {
collectionView.leadingAnchor.constraint(equalTo: mainView.leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: mainView.trailingAnchor),
collectionView.topAnchor.constraint(equalTo: mainView.topAnchor, constant: navigationBarHeight),
collectionView.bottomAnchor.constraint(equalTo: paymentInfoContainerView.topAnchor, constant: Constants.collectionViewBottomPadding),

pageControl.heightAnchor.constraint(equalToConstant: Constants.pageControlHeight),
pageControl.bottomAnchor.constraint(equalTo: collectionView.bottomAnchor, constant: -Constants.collectionViewPadding),
Expand Down Expand Up @@ -530,6 +533,68 @@ extension PaymentReviewViewController {
}
}

extension PaymentReviewViewController {
private func setupInitialLayout() {
updateLayoutForCurrentOrientation()
}

private func updateLayoutForCurrentOrientation() {
let deviceOrientation = UIDevice.current.orientation
switch deviceOrientation {
case .portrait:
setupPortraitConstraints()
case .landscapeLeft, .landscapeRight:
setupLandscapeConstraints()
default:
break
}
collectionView.reloadData()
}

private func setupPortraitConstraints() {
setupConstraints(for: .vertical)
}

private func setupLandscapeConstraints() {
setupConstraints(for: .horizontal)
}

private func setupConstraints(for orientation: NSLayoutConstraint.Axis) {
// Deactivate previous constraints
NSLayoutConstraint.deactivate(orientation == .vertical ? landscapeConstraints : portraitConstraints)

paymentInfoContainerView.setupView()

let isPortrait = orientation == .vertical
let showCollectionView = model.displayMode == .documentCollection

var constraints = [] as [NSLayoutConstraint]

if showCollectionView {
constraints.append(collectionView.bottomAnchor.constraint(equalTo: isPortrait ? paymentInfoContainerView.topAnchor : mainView.bottomAnchor, constant: Constants.collectionViewBottomPadding))
}

if isPortrait {
portraitConstraints = constraints
NSLayoutConstraint.activate(portraitConstraints)
} else {
landscapeConstraints = constraints
NSLayoutConstraint.activate(landscapeConstraints)
}
}

// Handle orientation change
public override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
updateLayoutForCurrentOrientation()

// Perform layout updates with animation
coordinator.animate(alongsideTransition: { context in
self.view.layoutIfNeeded()
}, completion: nil)
}
}

extension PaymentReviewViewController {
enum Constants {
static let animationDuration = 0.3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,16 @@ open class ZoomedImageView: UIScrollView {
setMaxMinZoomScalesForCurrentBounds()
zoomScale = minimumZoomScale

let deviceOrientation = UIDevice.current.orientation
switch deviceOrientation {
case .portrait:
imageContentMode = .aspectFit
case .landscapeLeft, .landscapeRight:
imageContentMode = .widthFill
default:
break
}

switch initialOffset {
case .begining:
contentOffset = CGPoint.zero
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,21 @@ public final class PaymentReviewContainerView: UIView {
private let recipientStackView = EmptyStackView().orientation(.vertical).distribution(.fill)
private let ibanAmountContainerStackView = EmptyStackView().orientation(.vertical).distribution(.fill)
private let ibanAmountHorizontalStackView = EmptyStackView().orientation(.horizontal).distribution(.fill).spacing(Constants.stackViewSpacing)

private let firstStackContainerView = EmptyStackView().orientation(.vertical).distribution(.fill)
private let firstStackHorizontalStackView = EmptyStackView().orientation(.horizontal).distribution(.fillEqually).spacing(Constants.stackViewSpacing)
private let firstErrorsHorizontalStackView = EmptyStackView().orientation(.horizontal).distribution(.fillEqually)

private let secondStackContainerView = EmptyStackView().orientation(.vertical).distribution(.fill)
private let secondStackHorizontalStackView = EmptyStackView().orientation(.horizontal).distribution(.fill).spacing(Constants.stackViewSpacing)
private let secondErrorsHorizontalStackView = EmptyStackView().orientation(.horizontal).distribution(.fill)

private let ibanAmountErrorsHorizontalStackView = EmptyStackView().orientation(.horizontal).distribution(.fill)
private let recipientErrorStackView = EmptyStackView().orientation(.vertical).distribution(.fill)
private let ibanErrorStackView = EmptyStackView().orientation(.vertical).distribution(.fill)
private let amountErrorStackView = EmptyStackView().orientation(.vertical).distribution(.fill)
private let usageStackView = EmptyStackView().orientation(.vertical).distribution(.fill)
private let usageErrorStackView = EmptyStackView().orientation(.vertical).distribution(.fill)

private lazy var recipientTextFieldView = buildTextFieldWithLabelView(tag: TextFieldType.recipientFieldTag.rawValue, isEditable: !viewModel.configuration.lockedFields)
private lazy var ibanTextFieldView = buildTextFieldWithLabelView(tag: TextFieldType.ibanFieldTag.rawValue, isEditable: !viewModel.configuration.lockedFields)
Expand Down Expand Up @@ -78,6 +88,8 @@ public final class PaymentReviewContainerView: UIView {
private var paymentInputFields: [TextFieldWithLabelView] = []
private var paymentInputFieldsErrorLabels: [UILabel] = []
private var coupledErrorLabels: [UILabel] = []
private var firstCoupledErrorsLabels: [UILabel] = []
private var secondCoupleErrorsLabels: [UILabel] = []
private let viewModel: PaymentReviewContainerViewModel
/// A closure that is called when the pay button is clicked.
public var onPayButtonClicked: (() -> Void)?
Expand All @@ -87,36 +99,71 @@ public final class PaymentReviewContainerView: UIView {
public init(viewModel: PaymentReviewContainerViewModel) {
self.viewModel = viewModel
super.init(frame: .zero)
setupViewHierarchy()
setupLayout()
setupView()
}

public func setupView() {
let isPortrait = UIDevice.current.orientation.isPortrait
setupViewHierarchy(isPortrait: isPortrait)
setupLayout(isPortrait: isPortrait)
configureUI()
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

private func setupViewHierarchy() {
private func setupViewHierarchy(isPortrait: Bool) {
paymentInputFields = [recipientTextFieldView, amountTextFieldView, ibanTextFieldView, usageTextFieldView]
paymentInputFieldsErrorLabels = [recipientErrorLabel, amountErrorLabel, ibanErrorLabel, usageErrorLabel]
coupledErrorLabels = [amountErrorLabel, ibanErrorLabel]

recipientStackView.addArrangedSubview(recipientTextFieldView)
recipientStackView.addArrangedSubview(recipientErrorLabel)

ibanAmountHorizontalStackView.addArrangedSubview(ibanTextFieldView)
ibanAmountHorizontalStackView.addArrangedSubview(amountTextFieldView)

ibanErrorStackView.addArrangedSubview(ibanErrorLabel)
amountErrorStackView.addArrangedSubview(amountErrorLabel)
ibanAmountErrorsHorizontalStackView.addArrangedSubview(ibanErrorStackView)
ibanAmountErrorsHorizontalStackView.addArrangedSubview(amountErrorStackView)

ibanAmountContainerStackView.addArrangedSubview(ibanAmountHorizontalStackView)
ibanAmountContainerStackView.addArrangedSubview(ibanAmountErrorsHorizontalStackView)

usageStackView.addArrangedSubview(usageTextFieldView)
usageStackView.addArrangedSubview(usageErrorLabel)
if isPortrait {
coupledErrorLabels = [amountErrorLabel, ibanErrorLabel]
} else {
firstCoupledErrorsLabels = [recipientErrorLabel, ibanErrorLabel]
secondCoupleErrorsLabels = [amountErrorLabel, usageErrorLabel]
}

if isPortrait {
recipientStackView.addArrangedSubview(recipientTextFieldView)
recipientStackView.addArrangedSubview(recipientErrorLabel)

ibanAmountHorizontalStackView.addArrangedSubview(ibanTextFieldView)
ibanAmountHorizontalStackView.addArrangedSubview(amountTextFieldView)

ibanErrorStackView.addArrangedSubview(ibanErrorLabel)
amountErrorStackView.addArrangedSubview(amountErrorLabel)
ibanAmountErrorsHorizontalStackView.addArrangedSubview(ibanErrorStackView)
ibanAmountErrorsHorizontalStackView.addArrangedSubview(amountErrorStackView)

ibanAmountContainerStackView.addArrangedSubview(ibanAmountHorizontalStackView)
ibanAmountContainerStackView.addArrangedSubview(ibanAmountErrorsHorizontalStackView)

usageStackView.addArrangedSubview(usageTextFieldView)
usageStackView.addArrangedSubview(usageErrorLabel)
} else {

firstStackHorizontalStackView.addArrangedSubview(recipientTextFieldView)
firstStackHorizontalStackView.addArrangedSubview(ibanTextFieldView)

recipientErrorStackView.addArrangedSubview(recipientErrorLabel)
ibanErrorStackView.addArrangedSubview(ibanErrorLabel)
firstErrorsHorizontalStackView.addArrangedSubview(recipientErrorStackView)
firstErrorsHorizontalStackView.addArrangedSubview(ibanErrorStackView)

secondStackHorizontalStackView.addArrangedSubview(amountTextFieldView)
secondStackHorizontalStackView.addArrangedSubview(usageTextFieldView)

amountErrorStackView.addArrangedSubview(amountErrorLabel)
usageErrorStackView.addArrangedSubview(usageErrorLabel)
secondErrorsHorizontalStackView.addArrangedSubview(amountErrorStackView)
secondErrorsHorizontalStackView.addArrangedSubview(usageErrorStackView)

firstStackContainerView.addArrangedSubview(firstStackHorizontalStackView)
firstStackContainerView.addArrangedSubview(firstErrorsHorizontalStackView)

secondStackContainerView.addArrangedSubview(secondStackHorizontalStackView)
secondStackContainerView.addArrangedSubview(secondErrorsHorizontalStackView)
}

if viewModel.configuration.showBanksPicker {
buttonsStackView.addArrangedSubview(selectBankButton)
Expand All @@ -127,12 +174,16 @@ public final class PaymentReviewContainerView: UIView {
bottomStackView.addArrangedSubview(UIView())
bottomStackView.addArrangedSubview(poweredByGiniView)
bottomView.addSubview(bottomStackView)

paymentInfoStackView.addArrangedSubview(recipientStackView)

paymentInfoStackView.addArrangedSubview(ibanAmountContainerStackView)

paymentInfoStackView.addArrangedSubview(usageStackView)

paymentInfoStackView.removeAllArrangedSubviews()
if isPortrait {
paymentInfoStackView.addArrangedSubview(recipientStackView)
paymentInfoStackView.addArrangedSubview(ibanAmountContainerStackView)
paymentInfoStackView.addArrangedSubview(usageStackView)
} else {
paymentInfoStackView.addArrangedSubview(firstStackContainerView)
paymentInfoStackView.addArrangedSubview(secondStackContainerView)
}
paymentInfoStackView.addArrangedSubview(buttonsView)
paymentInfoStackView.addArrangedSubview(bottomView)
paymentInfoStackView.addArrangedSubview(UIView())
Expand All @@ -142,11 +193,16 @@ public final class PaymentReviewContainerView: UIView {

// MARK: Layout & Constraints

private func setupLayout() {
private func setupLayout(isPortrait: Bool) {
setupContainerContraints()
setupRecipientStackViewConstraints()
setupIbanAmountStackViewsConstraints()
setupUsageStackViewConstraints()
if isPortrait {
setupRecipientStackViewConstraints()
setupIbanAmountStackViewsConstraints()
setupUsageStackViewConstraints()
} else {
setupFirstStackViewsConstraints()
setupSecondStackViewsConstraints()
}
setupButtonConstraints()
setupPoweredByGiniConstraints()
}
Expand Down Expand Up @@ -198,6 +254,30 @@ public final class PaymentReviewContainerView: UIView {
usageErrorLabel.heightAnchor.constraint(equalToConstant: Constants.errorLabelHeight)
])
}

private func setupFirstStackViewsConstraints() {
NSLayoutConstraint.activate([
ibanTextFieldView.heightAnchor.constraint(equalToConstant: Constants.textFieldHeight),
amountTextFieldView.heightAnchor.constraint(equalToConstant: Constants.textFieldHeight),
ibanErrorLabel.heightAnchor.constraint(equalToConstant: Constants.errorLabelHeight),
amountErrorLabel.heightAnchor.constraint(equalToConstant: Constants.errorLabelHeight),
])
}

private func setupSecondStackViewsConstraints() {
let amountTextFieldWidthConstraint = amountTextFieldView.widthAnchor.constraint(greaterThanOrEqualToConstant: Constants.amountWidth)
amountTextFieldWidthConstraint.priority = .required - 1
let amountErrorLabelWidthConstraint = amountErrorLabel.widthAnchor.constraint(equalToConstant: Constants.amountWidth)
amountTextFieldWidthConstraint.priority = .required - 1
NSLayoutConstraint.activate([
amountTextFieldView.heightAnchor.constraint(equalToConstant: Constants.textFieldHeight),
usageTextFieldView.heightAnchor.constraint(equalToConstant: Constants.textFieldHeight),
amountTextFieldWidthConstraint,
usageErrorLabel.heightAnchor.constraint(equalToConstant: Constants.errorLabelHeight),
amountErrorLabel.heightAnchor.constraint(equalToConstant: Constants.errorLabelHeight),
amountErrorLabelWidthConstraint
])
}

private func setupButtonConstraints() {
NSLayoutConstraint.activate([
Expand Down Expand Up @@ -518,7 +598,14 @@ public final class PaymentReviewContainerView: UIView {
private func updateAmountIbanErrorState() {
ibanAmountErrorsHorizontalStackView.isHidden = coupledErrorLabels.allSatisfy { $0.isHidden }
}

private func updateRecipientIbanErrorState() {
firstErrorsHorizontalStackView.isHidden = firstCoupledErrorsLabels.allSatisfy { $0.isHidden }
}

private func updateAmountUsageErrorState() {
secondErrorsHorizontalStackView.isHidden = secondCoupleErrorsLabels.allSatisfy { $0.isHidden }
}
// MARK: - Pay Button Action
fileprivate func payButtonClicked() {
self.endEditing(true)
Expand Down

0 comments on commit 302ee68

Please sign in to comment.