Dibya
2 years ago
64 changed files with 2903 additions and 530 deletions
-
92GME Remit.xcodeproj/project.pbxproj
-
11GME Remit/Extensions/String+Ext.swift
-
8GME Remit/Extensions/UIColor+Ext.swift
-
30GME Remit/Extensions/UIFont+Ext.swift
-
110GME Remit/Extensions/UIView+Ext.swift
-
4GME Remit/Modules/ExchangeRates/Application Logic/Interactor/ExchangeRatesInteractorIO.swift
-
28GME Remit/Modules/ExchangeRates/User Interface/Presenter/ExchangeRatesPresenter.swift
-
3GME Remit/Modules/ExchangeRates/User Interface/View/ExchangeRatesViewController.swift
-
72GME Remit/Modules/Home/Application Logic/Interactor/HomeInteractor.swift
-
11GME Remit/Modules/Home/Application Logic/Interactor/HomeInteractorIO.swift
-
4GME Remit/Modules/Home/Module Interface/HomeModuleInterface.swift
-
25GME Remit/Modules/Home/User Interface/Presenter/HomePresenter.swift
-
67GME Remit/Modules/Home/User Interface/View/Cell/CarouselCell.swift
-
10GME Remit/Modules/Home/User Interface/View/Cell/HomeCollectionCollectionViewCell.swift
-
183GME Remit/Modules/Home/User Interface/View/Cell/HomeCollectionTableViewCell.swift
-
89GME Remit/Modules/Home/User Interface/View/Cell/HomeExchangeRateCollectionViewCell.swift
-
47GME Remit/Modules/Home/User Interface/View/Cell/HomeRemainingLimitTableViewCell.swift
-
184GME Remit/Modules/Home/User Interface/View/Custom/HomeAccountDetailView.swift
-
207GME Remit/Modules/Home/User Interface/View/Custom/HomeCarouselView.swift
-
527GME Remit/Modules/Home/User Interface/View/Custom/HomeExchangeRateView.swift
-
457GME Remit/Modules/Home/User Interface/View/Home.storyboard
-
244GME Remit/Modules/Home/User Interface/View/HomeViewController.swift
-
221GME Remit/Modules/Home/User Interface/View/HomeViewControllerNew.swift
-
7GME Remit/Modules/Home/User Interface/View/HomeViewInterface.swift
-
5GME Remit/Modules/Home/User Interface/Wireframe/HomeWireframe.swift
-
21GME Remit/Modules/Main/User Interface/View/MainViewController.swift
-
21GME Remit/Supported Files/Assets.xcassets/customer_support_new.imageset/Contents.json
-
14GME Remit/Supported Files/Assets.xcassets/customer_support_new.imageset/Group 10616.svg
-
21GME Remit/Supported Files/Assets.xcassets/exchangeRateButton.imageset/Contents.json
-
10GME Remit/Supported Files/Assets.xcassets/exchangeRateButton.imageset/exchangeRateButton.svg
-
21GME Remit/Supported Files/Assets.xcassets/exchange_rate_guranteed.imageset/Contents.json
-
11GME Remit/Supported Files/Assets.xcassets/exchange_rate_guranteed.imageset/guranteed.svg
-
21GME Remit/Supported Files/Assets.xcassets/exchange_rate_transfer_fee.imageset/Contents.json
-
14GME Remit/Supported Files/Assets.xcassets/exchange_rate_transfer_fee.imageset/transfer.svg
-
21GME Remit/Supported Files/Assets.xcassets/ic_notification_dot_new.imageset/Contents.json
-
15GME Remit/Supported Files/Assets.xcassets/ic_notification_dot_new.imageset/Group 10556.svg
-
21GME Remit/Supported Files/Assets.xcassets/notification_bell_new.imageset/Contents.json
-
9GME Remit/Supported Files/Assets.xcassets/notification_bell_new.imageset/Group 10401.svg
-
6GME Remit/Supported Files/Assets.xcassets/tabbar/Contents.json
-
21GME Remit/Supported Files/Assets.xcassets/tabbar/tab-contact-selected.imageset/Contents.json
-
8GME Remit/Supported Files/Assets.xcassets/tabbar/tab-contact-selected.imageset/style_black_24dp.svg
-
21GME Remit/Supported Files/Assets.xcassets/tabbar/tab-contact.imageset/Contents.json
-
8GME Remit/Supported Files/Assets.xcassets/tabbar/tab-contact.imageset/style_black_24dp (1).svg
-
21GME Remit/Supported Files/Assets.xcassets/tabbar/tab-home-selected.imageset/Contents.json
-
10GME Remit/Supported Files/Assets.xcassets/tabbar/tab-home-selected.imageset/Group 10878.svg
-
21GME Remit/Supported Files/Assets.xcassets/tabbar/tab-home.imageset/Contents.json
-
10GME Remit/Supported Files/Assets.xcassets/tabbar/tab-home.imageset/Group 10877.svg
-
27GME Remit/Supported Files/Info.plist
-
BINGME Remit/Supported Files/Volte/volte-bold.otf
-
BINGME Remit/Supported Files/Volte/volte-bolditalic.otf
-
BINGME Remit/Supported Files/Volte/volte-light.otf
-
BINGME Remit/Supported Files/Volte/volte-lightitalic.otf
-
BINGME Remit/Supported Files/Volte/volte-medium.otf
-
BINGME Remit/Supported Files/Volte/volte-mediumitalic.otf
-
BINGME Remit/Supported Files/Volte/volte-regular.otf
-
BINGME Remit/Supported Files/Volte/volte-regularitalic.otf
-
BINGME Remit/Supported Files/Volte/volte-semibold.otf
-
BINGME Remit/Supported Files/Volte/volte-semibolditalic.otf
-
95GME Remit/Utilities/CustomUI/CurrencyTextField.swift
-
130GME Remit/Utilities/CustomUI/CustomPageControl.swift
-
172GME Remit/Utilities/ExchangeRateCustomView.swift
-
6GME Remit/Utilities/TabBar Helper/CustomItemTabView.swift
-
3GME Remit/Utilities/TabBar Helper/CustomTabBar.swift
-
8GME Remit/Utilities/TabBar Helper/CustomTabItem.swift
@ -0,0 +1,67 @@ |
|||
// |
|||
|
|||
import Foundation |
|||
import UIKit |
|||
import SDWebImage |
|||
|
|||
|
|||
class CarouselCollectionCell: UICollectionViewCell{ |
|||
|
|||
static let identifier: String = "CarouselCollectionCellID" |
|||
|
|||
private let backgroundImgView: UIImageView = { |
|||
let view = UIImageView() |
|||
view.translatesAutoresizingMaskIntoConstraints = false |
|||
return view |
|||
}() |
|||
|
|||
private let containerView: UIView = { |
|||
let view = UIView() |
|||
view.backgroundColor = .clear |
|||
view.translatesAutoresizingMaskIntoConstraints = false |
|||
return view |
|||
}() |
|||
|
|||
|
|||
private let titleLabel: UILabel = { |
|||
let view = UILabel() |
|||
view.font = UIFont.sanfrancisco(.bold, size: 21) |
|||
view.textColor = .themeWhite |
|||
view.translatesAutoresizingMaskIntoConstraints = false |
|||
return view |
|||
}() |
|||
|
|||
|
|||
override init(frame: CGRect) { |
|||
super.init(frame: frame) |
|||
setup() |
|||
} |
|||
|
|||
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } |
|||
|
|||
private func setup(){ |
|||
containerView.backgroundColor = .blue |
|||
containerView.layer.cornerRadius = 10 |
|||
containerView.clipsToBounds = true |
|||
|
|||
contentView.addSubview(containerView) |
|||
containerView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true |
|||
containerView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true |
|||
containerView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16).isActive = true |
|||
containerView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16).isActive = true |
|||
|
|||
containerView.addSubview(backgroundImgView) |
|||
backgroundImgView.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true |
|||
backgroundImgView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor).isActive = true |
|||
backgroundImgView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true |
|||
backgroundImgView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor).isActive = true |
|||
|
|||
} |
|||
|
|||
func update(_ event: String){ |
|||
DispatchQueue.main.async { |
|||
//let imageUrl = UrlManager.sharedInstance.baseImageUrl + "/" + "\(event.imageUrl ?? "")" |
|||
self.backgroundImgView.sd_setImage(with: URL(string: event), placeholderImage: UIImage(named: "flag_bahamas")) |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,89 @@ |
|||
// |
|||
|
|||
import UIKit |
|||
class HomeExchangeRateCollectionViewCell: UICollectionViewCell { |
|||
|
|||
var paymentServiceMethod: PaymentServiceType? |
|||
var image: UIImage? |
|||
|
|||
private let iconView: UIImageView = { |
|||
let imageView = UIImageView() |
|||
imageView.translatesAutoresizingMaskIntoConstraints = false |
|||
imageView.heightAnchor.constraint(equalToConstant: 10).isActive = true |
|||
imageView.widthAnchor.constraint(equalToConstant: 10).isActive = true |
|||
return imageView |
|||
}() |
|||
|
|||
var availableServiceLabel: UILabel = { |
|||
let label = UILabel() |
|||
label.translatesAutoresizingMaskIntoConstraints = false |
|||
return label |
|||
}() |
|||
|
|||
private var stackView: UIStackView! |
|||
static var identifier: String { |
|||
return String(describing: self) |
|||
} |
|||
|
|||
override init(frame: CGRect) { |
|||
super.init(frame: frame) |
|||
setup() |
|||
} |
|||
|
|||
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } |
|||
|
|||
|
|||
private func setup() { |
|||
uiSetup() |
|||
uiPropertiesSetup() |
|||
} |
|||
|
|||
private func uiSetup(){ |
|||
stackView = UIStackView(arrangedSubviews: [iconView, availableServiceLabel]) |
|||
stackView.translatesAutoresizingMaskIntoConstraints = false |
|||
stackView.axis = .horizontal |
|||
stackView.distribution = .fill |
|||
stackView.spacing = 3 |
|||
stackView.alignment = .center |
|||
|
|||
contentView.addSubview(stackView) |
|||
stackView.anchor(top: contentView.topAnchor, |
|||
paddingTop: 8, |
|||
bottom: contentView.bottomAnchor, |
|||
paddingBottom: -8, |
|||
left: contentView.leadingAnchor, |
|||
paddingLeft: 8, |
|||
right: contentView.trailingAnchor, |
|||
paddingRight: -8 |
|||
) |
|||
|
|||
availableServiceLabel.font = .sanfrancisco(.semibold, size: 14) |
|||
} |
|||
|
|||
|
|||
|
|||
private func uiPropertiesSetup() { |
|||
contentView.set(cornerRadius: 16) |
|||
contentView.set(borderWidth: 2, of: .init(hex: "#00001F")) |
|||
|
|||
} |
|||
|
|||
func setup(cellSelected: Bool) { |
|||
iconView.image = image |
|||
availableServiceLabel.text = paymentServiceMethod?.subtitle |
|||
cellSelected ? showBorderColor() : hideBorderColor() |
|||
} |
|||
|
|||
private func showBorderColor() { |
|||
self.contentView.backgroundColor = .init(hex: "#2E89FF").withAlphaComponent(0.3) |
|||
contentView.set(borderWidth: 2, of: .init(hex: "#0052FF")) |
|||
self.layoutSubviews() |
|||
} |
|||
|
|||
private func hideBorderColor() { |
|||
self.contentView.backgroundColor = .themeWhite |
|||
contentView.set(borderWidth: 2, of: .themeGray1) |
|||
self.layoutSubviews() |
|||
} |
|||
|
|||
} |
@ -0,0 +1,184 @@ |
|||
|
|||
import UIKit |
|||
|
|||
class HomeAccountDetailView: UIView { |
|||
|
|||
private let accountDetailView: UIView = { |
|||
let view = UIView(frame: .zero) |
|||
view.backgroundColor = .themeWhite |
|||
view.translatesAutoresizingMaskIntoConstraints = false |
|||
return view |
|||
}() |
|||
|
|||
private let accountNumberTitleLabel: UILabel = { |
|||
let label = UILabel() |
|||
label.translatesAutoresizingMaskIntoConstraints = false |
|||
return label |
|||
}() |
|||
|
|||
private let accountNumberValueLabel: UILabel = { |
|||
let label = UILabel() |
|||
label.translatesAutoresizingMaskIntoConstraints = false |
|||
return label |
|||
}() |
|||
|
|||
private let balanceTitleLabel: UILabel = { |
|||
let label = UILabel() |
|||
label.translatesAutoresizingMaskIntoConstraints = false |
|||
return label |
|||
}() |
|||
|
|||
private var balanceValueLabel: UILabel = { |
|||
let label = UILabel() |
|||
label.translatesAutoresizingMaskIntoConstraints = false |
|||
return label |
|||
}() |
|||
|
|||
private let copyButton: UIButton = { |
|||
let button = UIButton() |
|||
button.translatesAutoresizingMaskIntoConstraints = false |
|||
return button |
|||
}() |
|||
|
|||
private let uploadSlipButton: UIButton = { |
|||
let button = UIButton() |
|||
button.translatesAutoresizingMaskIntoConstraints = false |
|||
return button |
|||
}() |
|||
|
|||
private let exchangeRateView: UIView = { |
|||
let view = UIView() |
|||
view.translatesAutoresizingMaskIntoConstraints = false |
|||
return view |
|||
}() |
|||
|
|||
|
|||
override init(frame: CGRect) { |
|||
super.init(frame: .zero) |
|||
setup() |
|||
} |
|||
|
|||
// override func awakeFromNib() { |
|||
// super.awakeFromNib() |
|||
// setup() |
|||
// } |
|||
|
|||
required init?(coder: NSCoder) { |
|||
super.init(coder: coder) |
|||
fatalError("init(coder:) has not been implemented") |
|||
} |
|||
|
|||
func setup() { |
|||
uiSetup() |
|||
uiPropertiesSetup() |
|||
} |
|||
|
|||
private func uiSetup() { |
|||
|
|||
self.addSubview(accountDetailView) |
|||
accountDetailView.anchor(top: self.topAnchor, |
|||
paddingTop: 0, |
|||
bottom: self.bottomAnchor, |
|||
paddingBottom: 0, |
|||
left: self.leadingAnchor, |
|||
paddingLeft: 0, |
|||
right: self.trailingAnchor, |
|||
paddingRight: 0, |
|||
width: 0, |
|||
height: 0) |
|||
|
|||
accountDetailView.addSubviews(accountNumberTitleLabel, |
|||
accountNumberValueLabel, |
|||
balanceTitleLabel, |
|||
balanceValueLabel, |
|||
copyButton, |
|||
uploadSlipButton) |
|||
accountDetailView.addShadow() |
|||
|
|||
accountNumberTitleLabel.anchor(top: accountDetailView.topAnchor, |
|||
paddingTop: 16, |
|||
bottom: nil, |
|||
paddingBottom: 0, |
|||
left: accountDetailView.leadingAnchor, paddingLeft: 16, |
|||
right: accountDetailView.trailingAnchor, paddingRight: -16) |
|||
|
|||
accountNumberValueLabel.anchor(top: accountNumberTitleLabel.bottomAnchor, |
|||
paddingTop: 4, |
|||
bottom: nil, |
|||
paddingBottom: 0, |
|||
left: accountDetailView.leadingAnchor, |
|||
paddingLeft: 16 |
|||
) |
|||
|
|||
copyButton.anchor(top: nil, |
|||
bottom: nil, |
|||
left: accountNumberValueLabel.trailingAnchor, |
|||
paddingLeft: 4, |
|||
width: 80, |
|||
height: 80 |
|||
) |
|||
|
|||
copyButton.center(centerX: nil, |
|||
paddingX: 0, |
|||
centerY: accountNumberValueLabel.centerYAnchor, |
|||
paddingY: 0) |
|||
|
|||
copyButton.anchorLessThanEqualTo(right: accountDetailView.trailingAnchor, |
|||
paddingRight: -16) |
|||
|
|||
balanceTitleLabel.anchor(top: accountNumberValueLabel.bottomAnchor, |
|||
paddingTop: 16, |
|||
left: accountDetailView.leadingAnchor, |
|||
paddingLeft: 16) |
|||
|
|||
balanceValueLabel.anchor(top: balanceTitleLabel.bottomAnchor, |
|||
paddingTop: 4, |
|||
bottom: accountDetailView.bottomAnchor, |
|||
paddingBottom: -16, |
|||
left: accountDetailView.leadingAnchor, |
|||
paddingLeft: 16) |
|||
|
|||
uploadSlipButton.anchor(top: balanceTitleLabel.topAnchor, |
|||
bottom: balanceValueLabel.bottomAnchor, |
|||
right: accountDetailView.trailingAnchor, |
|||
paddingRight: -16 |
|||
) |
|||
|
|||
} |
|||
|
|||
func uiPropertiesSetup() { |
|||
|
|||
accountDetailView.setupCornerRadius(20,maskedCorners: [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]) |
|||
|
|||
accountNumberTitleLabel.text = "account_number_text".localized() |
|||
copyButton.setTitle("Copy", for: .normal) |
|||
copyButton.setTitleColor(.red, for: .normal) |
|||
|
|||
balanceTitleLabel.text = "domestic_available_balance_text".localized() |
|||
balanceValueLabel.text = "6482682342" |
|||
|
|||
uploadSlipButton.backgroundColor = .red |
|||
uploadSlipButton.set(cornerRadius: 5) |
|||
uploadSlipButton.setImage(UIImage(named: "chat"), for: .normal) |
|||
uploadSlipButton.setTitle("Upload", for: .normal) |
|||
uploadSlipButton.setTitleColor(.green, for: .normal) |
|||
uploadSlipButton.contentEdgeInsets = UIEdgeInsets(top: 10, |
|||
left: 10, |
|||
bottom: 10, |
|||
right: 20) |
|||
|
|||
} |
|||
|
|||
func setupData() { |
|||
let availableBalance = GMEDB.shared.user.string(.availableBalance) |
|||
balanceValueLabel.text = availableBalance |
|||
let walletNumber = GMEDB.shared.user.string(.referralCode) ?? "" |
|||
accountNumberValueLabel.text = walletNumber == "" ? "N/A" : walletNumber |
|||
} |
|||
|
|||
func setAmount(_ amount: String) { |
|||
balanceValueLabel.text = amount |
|||
} |
|||
|
|||
|
|||
} |
@ -0,0 +1,207 @@ |
|||
// |
|||
|
|||
import Foundation |
|||
import UIKit |
|||
|
|||
class HomeCarouselView: UIView { |
|||
|
|||
private var events: [String] = [] |
|||
private var timer: Timer? |
|||
|
|||
private let collectionView: UICollectionView = { |
|||
let flowlayout = UICollectionViewFlowLayout() |
|||
flowlayout.scrollDirection = .horizontal |
|||
|
|||
let view = UICollectionView(frame: CGRect.zero, collectionViewLayout: flowlayout) |
|||
view.register(CarouselCollectionCell.self, forCellWithReuseIdentifier: CarouselCollectionCell.identifier) |
|||
view.backgroundColor = .white |
|||
view.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) |
|||
view.showsHorizontalScrollIndicator = false |
|||
view.translatesAutoresizingMaskIntoConstraints = false |
|||
view.isPagingEnabled = true |
|||
return view |
|||
}() |
|||
|
|||
private let pageControl: CustomPageControl = { |
|||
let view = CustomPageControl(frame: .zero) |
|||
view.currentPageIndicatorTintColor = .themeBlack |
|||
view.pageIndicatorTintColor = .themeGray2 |
|||
view.translatesAutoresizingMaskIntoConstraints = false |
|||
return view |
|||
}() |
|||
|
|||
static let identifier: String = "HomeCarouselCellID" |
|||
|
|||
/// whether or not dragging has ended |
|||
fileprivate var endDragging = false |
|||
|
|||
/// the current page |
|||
@objc open dynamic var currentIndex: Int = 0 { |
|||
didSet { |
|||
updateAccessoryViews() |
|||
} |
|||
} |
|||
|
|||
|
|||
func updateAccessoryViews() { |
|||
pageControl.currentPage = currentIndex |
|||
|
|||
} |
|||
|
|||
|
|||
override init(frame: CGRect) { |
|||
super.init(frame: .zero) |
|||
setup() |
|||
} |
|||
|
|||
required init?(coder: NSCoder) { |
|||
fatalError("init(coder:) has not been implemented") |
|||
} |
|||
|
|||
|
|||
private func setup(){ |
|||
self.backgroundColor = .themeWhite |
|||
self.addSubview(pageControl) |
|||
pageControl.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true |
|||
pageControl.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true |
|||
pageControl.heightAnchor.constraint(equalToConstant: 30).isActive = true |
|||
|
|||
self.addSubview(collectionView) |
|||
collectionView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 0).isActive = true |
|||
collectionView.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 0).isActive = true |
|||
collectionView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true |
|||
collectionView.bottomAnchor.constraint(equalTo: pageControl.topAnchor, constant: 0).isActive = true |
|||
|
|||
collectionView.delegate = self |
|||
collectionView.dataSource = self |
|||
} |
|||
|
|||
override open func layoutSubviews() { |
|||
super.layoutSubviews() |
|||
collectionView.performBatchUpdates(nil, completion: nil) |
|||
moveToPage(currentIndex, animated: false) |
|||
} |
|||
|
|||
open func moveToPage(_ page: Int, animated: Bool) { |
|||
// outside the range |
|||
if page < 0 || page >= collectionView.numberOfItems(inSection: 0) { |
|||
return |
|||
} |
|||
|
|||
currentIndex = page |
|||
collectionView.scrollToItem(at: IndexPath(item: currentIndex, section: 0), |
|||
at: .left, animated: animated) |
|||
} |
|||
|
|||
|
|||
func update(_ events: [String]){ |
|||
self.events = events |
|||
pageControl.numberOfPages = events.count |
|||
self.collectionView.reloadData() |
|||
stopTimer() |
|||
startTimer() |
|||
} |
|||
|
|||
|
|||
/** |
|||
Scroll to Next Cell |
|||
*/ |
|||
@objc func scrollToNextCell(){ |
|||
let nextpage = self.currentIndex + 1 |
|||
if nextpage >= self.events.count{ |
|||
moveToPage(0, animated: true) |
|||
}else{ |
|||
moveToPage(nextpage, animated: true) |
|||
} |
|||
} |
|||
|
|||
/** |
|||
Invokes Timer to start Automatic Animation with repeat enabled |
|||
*/ |
|||
private func startTimer() { |
|||
self.timer = Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(self.scrollToNextCell), userInfo: nil, repeats: true) |
|||
} |
|||
|
|||
private func stopTimer(){ |
|||
self.timer?.invalidate() |
|||
self.timer = nil |
|||
} |
|||
|
|||
} |
|||
|
|||
//MARK:- UICollectionViewDelegate |
|||
extension HomeCarouselView: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{ |
|||
|
|||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { |
|||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CarouselCollectionCell.identifier, for: indexPath) as! CarouselCollectionCell |
|||
cell.update(self.events[indexPath.row]) |
|||
return cell |
|||
} |
|||
|
|||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { |
|||
return self.events.count |
|||
} |
|||
|
|||
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { |
|||
return CGSize(width: collectionView.frame.width, height: collectionView.frame.height) |
|||
} |
|||
|
|||
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { |
|||
return 0.001 |
|||
} |
|||
|
|||
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { |
|||
return 0.001 |
|||
} |
|||
|
|||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { |
|||
//self.didSelect?(self.events[indexPath.row]) |
|||
} |
|||
|
|||
|
|||
/** |
|||
size of the collection view |
|||
- parameter collectionView: the collection view |
|||
- parameter collectionViewLayout: the collection view flow layout |
|||
- parameter indexPath: the index path |
|||
*/ |
|||
// public func collectionView(_ collectionView: UICollectionView, |
|||
// layout collectionViewLayout: UICollectionViewLayout, |
|||
// sizeForItemAt indexPath: IndexPath) -> CGSize { |
|||
// return collectionView.bounds.size |
|||
// } |
|||
|
|||
/** |
|||
scroll view did end dragging |
|||
- parameter scrollView: the scroll view |
|||
- parameter decelerate: wether the view is decelerating or not. |
|||
*/ |
|||
public func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { |
|||
if !decelerate { |
|||
endScrolling(scrollView) |
|||
} else { |
|||
endDragging = true |
|||
} |
|||
} |
|||
|
|||
/** |
|||
Scroll view did end decelerating |
|||
*/ |
|||
public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { |
|||
if endDragging { |
|||
endDragging = false |
|||
endScrolling(scrollView) |
|||
} |
|||
} |
|||
|
|||
/** |
|||
end scrolling |
|||
*/ |
|||
fileprivate func endScrolling(_ scrollView: UIScrollView) { |
|||
let width = scrollView.bounds.width |
|||
let page = (scrollView.contentOffset.x + (0.5 * width)) / width |
|||
currentIndex = Int(page) |
|||
self.stopTimer() |
|||
self.startTimer() |
|||
} |
|||
} |
@ -0,0 +1,527 @@ |
|||
// |
|||
|
|||
import UIKit |
|||
|
|||
class HomeExchangeRateView: UIView { |
|||
|
|||
private let containerView: UIView = { |
|||
let view = UIView(frame: .zero) |
|||
view.backgroundColor = .themeWhite |
|||
view.translatesAutoresizingMaskIntoConstraints = false |
|||
return view |
|||
}() |
|||
|
|||
var sendMoneyView: ExchangeRateCustomView = { |
|||
let view = ExchangeRateCustomView(isReciver: false) |
|||
view.translatesAutoresizingMaskIntoConstraints = false |
|||
return view |
|||
}() |
|||
|
|||
|
|||
var recivedMoneyView: ExchangeRateCustomView = { |
|||
let view = ExchangeRateCustomView(isReciver: true) |
|||
view.isReciver = true |
|||
view.translatesAutoresizingMaskIntoConstraints = false |
|||
return view |
|||
}() |
|||
|
|||
|
|||
private let collectionView: UICollectionView = { |
|||
let flowlayout = UICollectionViewFlowLayout() |
|||
flowlayout.scrollDirection = .horizontal |
|||
flowlayout.collectionView?.showsHorizontalScrollIndicator = false |
|||
let view = UICollectionView(frame: CGRect.zero, collectionViewLayout: flowlayout) |
|||
view.translatesAutoresizingMaskIntoConstraints = false |
|||
view.register(HomeExchangeRateCollectionViewCell.self, forCellWithReuseIdentifier: HomeExchangeRateCollectionViewCell.identifier) |
|||
view.backgroundColor = .white |
|||
view.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) |
|||
return view |
|||
}() |
|||
|
|||
private let transferFeeIncludedImageView: UIImageView = { |
|||
let imageView = UIImageView() |
|||
imageView.image = UIImage(named: "exchange_rate_transfer_fee") |
|||
imageView.translatesAutoresizingMaskIntoConstraints = false |
|||
imageView.heightAnchor.constraint(equalToConstant: 24).isActive = true |
|||
imageView.widthAnchor.constraint(equalToConstant: 24).isActive = true |
|||
return imageView |
|||
}() |
|||
|
|||
private let transferFeeIncludedText: UILabel = { |
|||
let text = UILabel() |
|||
text.translatesAutoresizingMaskIntoConstraints = false |
|||
return text |
|||
}() |
|||
|
|||
private let guranteedRateImageView: UIImageView = { |
|||
let imageView = UIImageView() |
|||
imageView.image = UIImage(named: "exchange_rate_guranteed") |
|||
imageView.translatesAutoresizingMaskIntoConstraints = false |
|||
imageView.heightAnchor.constraint(equalToConstant: 24).isActive = true |
|||
imageView.widthAnchor.constraint(equalToConstant: 24).isActive = true |
|||
return imageView |
|||
}() |
|||
|
|||
private let guranteedRateText: UILabel = { |
|||
let text = UILabel() |
|||
text.translatesAutoresizingMaskIntoConstraints = false |
|||
return text |
|||
}() |
|||
|
|||
private let continueButton: UIButton = { |
|||
let button = UIButton() |
|||
button.translatesAutoresizingMaskIntoConstraints = false |
|||
button.heightAnchor.constraint(equalToConstant: 55).isActive = true |
|||
return button |
|||
}() |
|||
|
|||
private let exchangeButton: UIButton = { |
|||
let button = UIButton() |
|||
button.translatesAutoresizingMaskIntoConstraints = false |
|||
button.heightAnchor.constraint(equalToConstant: 32).isActive = true |
|||
button.widthAnchor.constraint(equalToConstant: 32).isActive = true |
|||
return button |
|||
}() |
|||
|
|||
//exRate |
|||
|
|||
private var transferFeeIncluded: UIStackView! |
|||
private var guranteedView: UIStackView! |
|||
|
|||
|
|||
|
|||
// MARK: Properties |
|||
private let edgeSpacing: CGFloat = 8.0 |
|||
private let itemSpacing: CGFloat = 8.0 |
|||
private var exchangeRateModels: [ExchangeRateModel]? |
|||
private var selectedExchangeRateModel: ExchangeRateModel? { |
|||
didSet { |
|||
selectedExchangeRateModel(selectedExchangeRateModel) |
|||
} |
|||
} |
|||
var calcBy = "" |
|||
var selectedPaymentModeIndex = 0 |
|||
var openCountryList: (() -> ())? |
|||
var tappedCalculateExchangeRate: ((ExchangeRateRequestModel) ->())? |
|||
|
|||
override init(frame: CGRect) { |
|||
super.init(frame: .zero) |
|||
setup() |
|||
} |
|||
|
|||
required init?(coder: NSCoder) { |
|||
fatalError("init(coder:) has not been implemented") |
|||
} |
|||
|
|||
func setup() { |
|||
uiSetup() |
|||
uiPropertiesSetup() |
|||
textChanged() |
|||
} |
|||
|
|||
func uiSetup() { |
|||
self.addSubview(containerView) |
|||
containerView.anchor(top: self.topAnchor, |
|||
paddingTop: 0, |
|||
bottom: self.bottomAnchor, |
|||
paddingBottom: 0, |
|||
left: self.leadingAnchor, |
|||
paddingLeft: 16, |
|||
right: self.trailingAnchor, |
|||
paddingRight: -16 |
|||
) |
|||
|
|||
transferFeeIncluded = UIStackView(arrangedSubviews: [transferFeeIncludedImageView, |
|||
transferFeeIncludedText]) |
|||
transferFeeIncluded.translatesAutoresizingMaskIntoConstraints = false |
|||
transferFeeIncluded.axis = .horizontal |
|||
transferFeeIncluded.spacing = 3 |
|||
transferFeeIncluded.distribution = .fill |
|||
|
|||
guranteedView = UIStackView(arrangedSubviews: [guranteedRateImageView, |
|||
guranteedRateText]) |
|||
guranteedView.translatesAutoresizingMaskIntoConstraints = false |
|||
guranteedView.axis = .horizontal |
|||
guranteedView.spacing = 3 |
|||
guranteedView.distribution = .fill |
|||
|
|||
|
|||
containerView.addSubviews(collectionView, |
|||
sendMoneyView, |
|||
exchangeButton, |
|||
recivedMoneyView, |
|||
transferFeeIncluded, |
|||
guranteedView, |
|||
continueButton) |
|||
collectionView.anchor( |
|||
top: containerView.topAnchor, |
|||
paddingTop: 0, |
|||
left: containerView.leadingAnchor, |
|||
paddingLeft: 0, |
|||
right: containerView.trailingAnchor, |
|||
paddingRight: 0, |
|||
height: 30 |
|||
) |
|||
|
|||
sendMoneyView.anchor( |
|||
top: collectionView.bottomAnchor, |
|||
paddingTop: 20, |
|||
left: containerView.leadingAnchor, |
|||
paddingLeft: 0, |
|||
right: containerView.trailingAnchor, |
|||
paddingRight: 0 |
|||
) |
|||
|
|||
recivedMoneyView.anchor( |
|||
top: sendMoneyView.bottomAnchor, |
|||
paddingTop: 16, |
|||
left: containerView.leadingAnchor, |
|||
paddingLeft: 0, |
|||
right: containerView.trailingAnchor, |
|||
paddingRight: 0 |
|||
) |
|||
|
|||
exchangeButton.anchor(top: sendMoneyView.bottomAnchor, |
|||
paddingTop: -8, |
|||
bottom: recivedMoneyView.topAnchor, |
|||
paddingBottom: 8, |
|||
left: sendMoneyView.leadingAnchor, |
|||
paddingLeft: 16) |
|||
|
|||
|
|||
transferFeeIncluded.anchor( |
|||
top: recivedMoneyView.bottomAnchor, |
|||
paddingTop: 16, |
|||
left: containerView.leadingAnchor, |
|||
paddingLeft: 0, |
|||
right: containerView.trailingAnchor, |
|||
paddingRight: 0 |
|||
) |
|||
|
|||
guranteedView.anchor( |
|||
top: transferFeeIncluded.bottomAnchor, |
|||
paddingTop: 16, |
|||
left: containerView.leadingAnchor, |
|||
paddingLeft: 0, |
|||
right: containerView.trailingAnchor, |
|||
paddingRight: 0 |
|||
) |
|||
|
|||
continueButton.anchor( |
|||
top: guranteedView.bottomAnchor, |
|||
paddingTop: 16, |
|||
left: containerView.leadingAnchor, |
|||
paddingLeft: 0, |
|||
right: containerView.trailingAnchor, |
|||
paddingRight: 0 |
|||
) |
|||
|
|||
continueButton.anchorLessThanEqualTo(bottom: containerView.bottomAnchor, paddingBottom: -16) |
|||
|
|||
} |
|||
|
|||
func uiPropertiesSetup() { |
|||
transferFeeIncludedText.text = "" |
|||
guranteedRateText.text = "" |
|||
continueButton.setTitle("continue_text".localized(), for: .normal) |
|||
continueButton.backgroundColor = .theme2E89FF |
|||
continueButton.titleLabel?.font = .sanfrancisco(.semibold, size: 20) |
|||
collectionView.delegate = self |
|||
collectionView.dataSource = self |
|||
continueButton.addTarget(self, action: #selector(calculateExchangeRate), for: .touchUpInside) |
|||
continueButton.set(cornerRadius: 10) |
|||
|
|||
sendMoneyView.set(borderWidth: 2, of: .black) |
|||
sendMoneyView.set(cornerRadius: 10) |
|||
sendMoneyView.title = "you_send_text".localized() |
|||
|
|||
recivedMoneyView.set(borderWidth: 2, of: .black) |
|||
recivedMoneyView.set(cornerRadius: 10) |
|||
recivedMoneyView.title = "receipient_gets_text".localized() |
|||
|
|||
exchangeButton.setTitle("", for: .normal) |
|||
exchangeButton.setImage(UIImage(named: "exchangeRateButton"), for: .normal) |
|||
exchangeButton.layer.cornerRadius = 10 |
|||
exchangeButton.backgroundColor = .themeGray1 |
|||
exchangeButton.layer.borderWidth = 2 |
|||
exchangeButton.layer.borderColor = UIColor.black.cgColor |
|||
|
|||
} |
|||
|
|||
func textChanged() { |
|||
sendMoneyView.passTextFieldText = { [weak self] text in |
|||
self?.calcBy = "c" |
|||
self?.recivedMoneyView.updatedText = "" |
|||
|
|||
} |
|||
|
|||
recivedMoneyView.passTextFieldText = { [weak self] text in |
|||
self?.calcBy = "p" |
|||
self?.sendMoneyView.updatedText = "" |
|||
} |
|||
|
|||
recivedMoneyView.didSelectCountry = { [weak self] in |
|||
self?.sendMoneyView.resignFirstResponder() |
|||
self?.recivedMoneyView.resignFirstResponder() |
|||
self?.openCountryList?() |
|||
} |
|||
} |
|||
|
|||
func set(_ model: [ExchangeRateModel]?) { |
|||
self.exchangeRateModels = model |
|||
setExchangeRateModels(model) |
|||
} |
|||
|
|||
func set(_ model: ExchangeRateDetailModel?) { |
|||
guard let model = model else { |
|||
return |
|||
} |
|||
|
|||
sendMoneyView.updatedText = model.senderAmount?.likeCommaMoney() |
|||
recivedMoneyView.updatedText = model.recipientAmount?.likeCommaMoney() |
|||
|
|||
let transferFee = ("\(model.transferFee?.likeCommaMoney() ?? "" ) JPY ") |
|||
.attributedText(color: .themeBlack, font: .sanfrancisco(.semibold, size: 14)) |
|||
|
|||
let transferInfo = "transfer_fee_included_text".localized().attributedText(color: .theme2E89FF, font: .sanfrancisco(.semibold, size: 14)) |
|||
|
|||
let transfer = NSMutableAttributedString() |
|||
|
|||
transfer.append(transferFee) |
|||
transfer.append(transferInfo) |
|||
|
|||
transferFeeIncludedText.attributedText = transfer |
|||
|
|||
let exchangeRate = model.exchangeRate ?? "" |
|||
let exchangeRateAttributed = ("1000 JPY = \(exchangeRate) \(selectedExchangeRateModel?.currency ?? "") ").attributedText(color: .themeBlack, font: .sanfrancisco(.semibold, size: 14)) |
|||
|
|||
let exchangeRateInfo = ("Guranteed rate for 24 hr").attributedText(color: .theme2E89FF, font: .sanfrancisco(.semibold, size: 14)) |
|||
|
|||
let gurrantedText = NSMutableAttributedString() |
|||
|
|||
gurrantedText.append(exchangeRateAttributed) |
|||
gurrantedText.append(exchangeRateInfo) |
|||
|
|||
guranteedRateText.attributedText = gurrantedText |
|||
} |
|||
|
|||
func set(_ model: ExchangeRateModel?) { |
|||
self.selectedExchangeRateModel = model |
|||
} |
|||
|
|||
private func setExchangeRateModels(_ model: [ExchangeRateModel]?) { |
|||
let countryCode = GMEDB.shared.user.string(.countryCode) |
|||
|
|||
if let defaultExchangeRate = model?.filter({ |
|||
($0.countryCode ?? "").lowercased() == countryCode?.lowercased() |
|||
}).first { |
|||
selectedExchangeRateModel = defaultExchangeRate |
|||
} else { |
|||
selectedExchangeRateModel = model?.filter({ |
|||
($0.countryCode ?? "").lowercased() == "az" |
|||
}).first |
|||
} |
|||
} |
|||
|
|||
private func selectedExchangeRateModel(_ model: ExchangeRateModel?) { |
|||
|
|||
let code = selectedExchangeRateModel?.countryCode?.lowercased() ?? "az" |
|||
let codeEnum = CountryEnum(rawValue: code) |
|||
|
|||
recivedMoneyView.flag = codeEnum?.flag |
|||
recivedMoneyView.currency = selectedExchangeRateModel?.currency |
|||
|
|||
guard let defaultAmount = codeEnum?.getDefaultRecipientAcount( |
|||
currency: selectedExchangeRateModel?.currency ?? "" |
|||
) else { |
|||
calcBy = "c" |
|||
sendMoneyView.updatedText = codeEnum?.defaultSenderAmount.likeCommaMoney() |
|||
recivedMoneyView.updatedText = "" |
|||
calculateExchangeRate() |
|||
return |
|||
} |
|||
calcBy = "p" |
|||
sendMoneyView.updatedText = "" |
|||
recivedMoneyView.updatedText = defaultAmount.likeCommaMoney() |
|||
|
|||
calculateExchangeRate() |
|||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { |
|||
self.collectionView.reloadData() |
|||
} |
|||
} |
|||
|
|||
@objc func calculateExchangeRate() { |
|||
let model = ExchangeRateRequestModel( |
|||
senderAmount: (sendMoneyView.text ?? sendMoneyView.updatedText ?? "").stringRemovingComma(), |
|||
senderCurrency: "JPY", |
|||
senderCountryID: "142", |
|||
recipientAmount: (recivedMoneyView.text ?? recivedMoneyView.updatedText ?? "").stringRemovingComma(), |
|||
recipientCurrency: selectedExchangeRateModel?.currency ?? "", |
|||
recipientCountryID: selectedExchangeRateModel?.countryId ?? "", |
|||
recipientCountry: selectedExchangeRateModel?.country ?? "", |
|||
serviceType: selectedExchangeRateModel? |
|||
.availableServices? |
|||
.elementAt(index: selectedPaymentModeIndex)?.id ?? "", |
|||
calcBy: calcBy |
|||
) |
|||
self.tappedCalculateExchangeRate?(model) |
|||
} |
|||
} |
|||
|
|||
extension HomeExchangeRateView: UICollectionViewDelegate, |
|||
UICollectionViewDataSource, |
|||
UICollectionViewDelegateFlowLayout { |
|||
|
|||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { |
|||
return self.selectedExchangeRateModel?.availableServices?.count ?? 0 |
|||
} |
|||
|
|||
func collectionView( |
|||
_ collectionView: UICollectionView, |
|||
cellForItemAt indexPath: IndexPath |
|||
) -> UICollectionViewCell { |
|||
let service = self.selectedExchangeRateModel?.availableServices?.elementAt(index: indexPath.row) |
|||
guard let index = PaymentMode.init(rawValue: service?.id ?? "") else { |
|||
return UICollectionViewCell() |
|||
} |
|||
|
|||
switch index { |
|||
case .bankDeposite: |
|||
return configureBankDepositeCell(collectionView: collectionView, indexPath: indexPath) |
|||
case .cashDelivery: |
|||
return configureCashDeliveryCell(collectionView: collectionView, indexPath: indexPath) |
|||
case .homeDelivery: |
|||
return configureHomeDeliveryCell(collectionView: collectionView, indexPath: indexPath) |
|||
case .mobileWallet: |
|||
return configureWalletDeliveryCell(collectionView: collectionView, indexPath: indexPath) |
|||
case .cardPayment: |
|||
return configureCardPaymentCell(collectionView: collectionView, indexPath: indexPath) |
|||
} |
|||
|
|||
} |
|||
|
|||
|
|||
func configureBankDepositeCell( |
|||
collectionView: UICollectionView, |
|||
indexPath: IndexPath |
|||
) -> UICollectionViewCell { |
|||
guard let cell = collectionView.dequeueReusableCell( |
|||
withReuseIdentifier: HomeExchangeRateCollectionViewCell.identifier, |
|||
for: indexPath |
|||
) as? HomeExchangeRateCollectionViewCell else { |
|||
return UICollectionViewCell() |
|||
} |
|||
|
|||
cell.paymentServiceMethod = self.selectedExchangeRateModel?.availableServices?.elementAt( |
|||
index: indexPath.row |
|||
) |
|||
|
|||
cell.image = UIImage(named: "bank_deposit") |
|||
cell.setup(cellSelected: self.selectedPaymentModeIndex == indexPath.row) |
|||
return cell |
|||
} |
|||
|
|||
func configureCardPaymentCell( |
|||
collectionView: UICollectionView, |
|||
indexPath: IndexPath |
|||
) -> UICollectionViewCell { |
|||
guard let cell = collectionView.dequeueReusableCell( |
|||
withReuseIdentifier: HomeExchangeRateCollectionViewCell.identifier, |
|||
for: indexPath |
|||
) as? HomeExchangeRateCollectionViewCell else { |
|||
return UICollectionViewCell() |
|||
} |
|||
|
|||
cell.paymentServiceMethod = self.selectedExchangeRateModel?.availableServices?.elementAt( |
|||
index: indexPath.row |
|||
) |
|||
|
|||
cell.image = #imageLiteral(resourceName: "ic_card_payment") |
|||
cell.setup(cellSelected: self.selectedPaymentModeIndex == indexPath.row) |
|||
return cell |
|||
} |
|||
|
|||
func configureWalletDeliveryCell( |
|||
collectionView: UICollectionView, |
|||
indexPath: IndexPath |
|||
) -> UICollectionViewCell { |
|||
guard let cell = collectionView.dequeueReusableCell( |
|||
withReuseIdentifier: HomeExchangeRateCollectionViewCell.identifier, |
|||
for: indexPath |
|||
) as? HomeExchangeRateCollectionViewCell else { |
|||
return UICollectionViewCell() |
|||
} |
|||
|
|||
cell.paymentServiceMethod = self.selectedExchangeRateModel?.availableServices?.elementAt( |
|||
index: indexPath.row |
|||
) |
|||
|
|||
cell.image = #imageLiteral(resourceName: "wallet-transfer") |
|||
cell.setup(cellSelected: self.selectedPaymentModeIndex == indexPath.row) |
|||
return cell |
|||
} |
|||
|
|||
func configureCashDeliveryCell( |
|||
collectionView: UICollectionView, |
|||
indexPath: IndexPath |
|||
) -> UICollectionViewCell { |
|||
guard let cell = collectionView.dequeueReusableCell( |
|||
withReuseIdentifier: HomeExchangeRateCollectionViewCell.identifier, |
|||
for: indexPath |
|||
) as? HomeExchangeRateCollectionViewCell else { |
|||
return UICollectionViewCell() |
|||
} |
|||
|
|||
cell.paymentServiceMethod = self.selectedExchangeRateModel?.availableServices?.elementAt( |
|||
index: indexPath.row |
|||
) |
|||
cell.image = UIImage(named: "cash_payment") |
|||
cell.setup(cellSelected: self.selectedPaymentModeIndex == indexPath.row) |
|||
return cell |
|||
} |
|||
|
|||
func configureHomeDeliveryCell( |
|||
collectionView: UICollectionView, |
|||
indexPath: IndexPath |
|||
) -> UICollectionViewCell { |
|||
guard let cell = collectionView.dequeueReusableCell( |
|||
withReuseIdentifier: HomeExchangeRateCollectionViewCell.identifier, |
|||
for: indexPath |
|||
) as? HomeExchangeRateCollectionViewCell else { |
|||
return UICollectionViewCell() |
|||
} |
|||
cell.paymentServiceMethod = self.selectedExchangeRateModel?.availableServices?.elementAt( |
|||
index: indexPath.row |
|||
) |
|||
|
|||
cell.image = #imageLiteral(resourceName: "ic_homeDelivery") |
|||
cell.setup(cellSelected: self.selectedPaymentModeIndex == indexPath.row) |
|||
return cell |
|||
} |
|||
|
|||
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { |
|||
let element = self.selectedExchangeRateModel?.availableServices?.elementAt( |
|||
index: indexPath.row)?.subtitle ?? "" |
|||
return CGSize(width: element.size(withAttributes: [NSAttributedString.Key.font : UIFont.sanfrancisco(.semibold, size: 16)]).width + 25, height: collectionView.frame.height) |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
// func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { |
|||
// let width = collectionView.frame.width |
|||
// |
|||
// let totalEdgeSpacing = edgeSpacing * 2 |
|||
// let numberOfItemsInRow = 3 |
|||
// let totalItemSpacing = CGFloat(numberOfItemsInRow - 1) * self.itemSpacing |
|||
// let size = (width - (totalEdgeSpacing + totalItemSpacing)) / CGFloat(numberOfItemsInRow) |
|||
// return CGSize(width: size, height: 60) |
|||
// } |
|||
|
|||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { |
|||
self.selectedPaymentModeIndex = indexPath.row |
|||
self.collectionView.reloadData() |
|||
self.calculateExchangeRate() |
|||
} |
|||
} |
|||
|
@ -0,0 +1,221 @@ |
|||
// |
|||
|
|||
import UIKit |
|||
import Localize_Swift |
|||
import LGSideMenuController |
|||
|
|||
class HomeViewControllerNew: UIViewController { |
|||
|
|||
var user: User? |
|||
var presenter: HomeModuleInterface? |
|||
var exchangeRateModels: [ExchangeRateModel]? |
|||
|
|||
// MARK: UIView |
|||
|
|||
private let scrollView: UIScrollView = { |
|||
let view = UIScrollView(frame: .zero) |
|||
view.translatesAutoresizingMaskIntoConstraints = false |
|||
view.backgroundColor = .themeWhite |
|||
return view |
|||
}() |
|||
|
|||
private let mainContainerView: UIView = { |
|||
let view = UIView(frame: .zero) |
|||
view.backgroundColor = .themeWhite |
|||
view.translatesAutoresizingMaskIntoConstraints = false |
|||
return view |
|||
}() |
|||
|
|||
private let accountDetailView: HomeAccountDetailView = { |
|||
let view = HomeAccountDetailView() |
|||
view.backgroundColor = .themeWhite |
|||
view.translatesAutoresizingMaskIntoConstraints = false |
|||
return view |
|||
}() |
|||
|
|||
private let exchangeRateView: HomeExchangeRateView = { |
|||
let view = HomeExchangeRateView() |
|||
view.translatesAutoresizingMaskIntoConstraints = false |
|||
return view |
|||
}() |
|||
|
|||
|
|||
init(){ |
|||
super.init(nibName: nil, bundle: nil) |
|||
} |
|||
|
|||
required init?(coder: NSCoder) { |
|||
fatalError("init(coder:) has not been implemented") |
|||
} |
|||
|
|||
override func viewDidLoad() { |
|||
super.viewDidLoad() |
|||
self.setup() |
|||
self.presenter?.fetchExchangeRate() |
|||
} |
|||
|
|||
override func viewWillAppear(_ animated: Bool) { |
|||
super.viewWillAppear(animated) |
|||
navigationController?.isNavigationBarHidden = true |
|||
self.navigationController?.setNavigationBarHidden(true, animated: animated) |
|||
} |
|||
|
|||
private func setup() { |
|||
hierarchySetup() |
|||
layoutSetup() |
|||
setupCallback() |
|||
} |
|||
|
|||
private func hierarchySetup() { |
|||
|
|||
view.addSubview(scrollView) |
|||
scrollView.addSubview(mainContainerView) |
|||
mainContainerView.addSubviews(accountDetailView, |
|||
exchangeRateView) |
|||
} |
|||
|
|||
func layoutSetup() { |
|||
scrollView.anchor(top: view.topAnchor, |
|||
paddingTop: 0, |
|||
bottom: view.bottomAnchor, |
|||
paddingBottom: 0, |
|||
left: view.leadingAnchor, |
|||
paddingLeft: 0, |
|||
right: view.trailingAnchor, |
|||
paddingRight: 0 |
|||
) |
|||
|
|||
mainContainerView.anchor(top: scrollView.topAnchor, |
|||
paddingTop: 0, |
|||
bottom: scrollView.bottomAnchor, |
|||
paddingBottom: 0, |
|||
left: scrollView.leadingAnchor, |
|||
paddingLeft: 0, |
|||
right: scrollView.trailingAnchor, |
|||
paddingRight: 0 |
|||
) |
|||
|
|||
mainContainerView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true |
|||
|
|||
accountDetailView.anchor(top: mainContainerView.topAnchor, |
|||
paddingTop: 0, |
|||
paddingBottom: 0, |
|||
left: mainContainerView.leadingAnchor, |
|||
paddingLeft: 0, |
|||
right: mainContainerView.trailingAnchor, |
|||
paddingRight: 0, |
|||
width: 0, |
|||
height: 0) |
|||
|
|||
exchangeRateView.anchor(top: accountDetailView.bottomAnchor, |
|||
paddingTop: 16, |
|||
bottom: mainContainerView.bottomAnchor, |
|||
paddingBottom: 0, |
|||
left: mainContainerView.leadingAnchor, |
|||
paddingLeft: 16, |
|||
right: mainContainerView.trailingAnchor, |
|||
paddingRight: -16, |
|||
width: 0, |
|||
height: 0) |
|||
|
|||
} |
|||
|
|||
private func setupCallback() { |
|||
exchangeRateView.openCountryList = { [weak self] in |
|||
self?.showCountryList() |
|||
} |
|||
|
|||
exchangeRateView.tappedCalculateExchangeRate = { [weak self] model in |
|||
self?.presenter?.exchangeCalculate(use: model) |
|||
} |
|||
} |
|||
|
|||
@objc func showCountryList() { |
|||
TablePresenterWireframe().openWith( |
|||
delegate: self, |
|||
model: exchangeRateModels, |
|||
source: self |
|||
) |
|||
} |
|||
|
|||
} |
|||
extension HomeViewControllerNew: HomeViewInterface { |
|||
func show(model: User, with rates: [ExchangeRateModel]?) { |
|||
|
|||
} |
|||
|
|||
func showOtpView() { |
|||
guard let viewController = UIStoryboard(name: "OtpVerification", bundle: nil) |
|||
.instantiateViewController(withIdentifier: "OtpVerificationViewController") as? OtpVerificationViewController else { |
|||
return |
|||
} |
|||
|
|||
//viewController.delegate = self |
|||
self.present(viewController, animated: true, completion: nil) |
|||
} |
|||
|
|||
func checkOtpError(error: String) { |
|||
self.alert(type: .error, message: error) |
|||
} |
|||
|
|||
func success() { |
|||
self.alertWithOk(type: .success, message: "OTP Verification completed", title: "success_text".localized(), okTitle: "ok_text".localized()) { |
|||
//self.presenter?.viewIsReady() |
|||
} |
|||
} |
|||
|
|||
func show(model: User) { |
|||
self.user = model |
|||
} |
|||
|
|||
func show(error: String) { |
|||
self.alert(type: .error, message: error) |
|||
} |
|||
|
|||
func show(panicError: String) { |
|||
self.alert(type: .error, message: panicError, title: "Warning") { |
|||
//self.presenter?.logout() |
|||
} |
|||
} |
|||
|
|||
func showLoading() { |
|||
self.showProgressHud() |
|||
} |
|||
|
|||
func hideLoading() { |
|||
self.hideProgressHud() |
|||
} |
|||
|
|||
func setModel(with model: [ExchangeRateModel]?) { |
|||
self.exchangeRateModels = model |
|||
exchangeRateView.set(model) |
|||
} |
|||
|
|||
func setModel(with model: ExchangeRateDetailModel?) { |
|||
exchangeRateView.set(model) |
|||
} |
|||
} |
|||
|
|||
// MARK: - TablePresenterDelegate |
|||
extension HomeViewControllerNew: TablePresenterDelegate { |
|||
func tablePresenterView(_ viewController: TablePresenterViewController) -> TablePresenterConfiguration { |
|||
return TablePresenterConfiguration( |
|||
presenterTitle: "search_currency_text".localized(), |
|||
closeButtonTitle: "cancel_text".localized(), |
|||
notFoundTitle: "no_result_found_text".localized(), |
|||
searchBarPlaceHolder: "search_currency_text".localized() |
|||
) |
|||
} |
|||
|
|||
func tablePresenterView( |
|||
_ viewController: TablePresenterViewController, |
|||
didSelectModel model: TablePresenterProtocol? |
|||
) { |
|||
if let exchangeRateModel = model as? ExchangeRateModel { |
|||
exchangeRateView.selectedPaymentModeIndex = 0 |
|||
exchangeRateView.set(exchangeRateModel) |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
@ -0,0 +1,21 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "1x" |
|||
}, |
|||
{ |
|||
"filename" : "Group 10616.svg", |
|||
"idiom" : "universal", |
|||
"scale" : "2x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "3x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"author" : "xcode", |
|||
"version" : 1 |
|||
} |
|||
} |
@ -0,0 +1,14 @@ |
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> |
|||
<g id="Group_10616" data-name="Group 10616" transform="translate(-320 -39)"> |
|||
<g id="Group_10401" data-name="Group 10401" transform="translate(152 5)"> |
|||
<rect id="Rectangle_2575" data-name="Rectangle 2575" width="24" height="24" transform="translate(168 34)" fill="none"/> |
|||
<g id="icons8-communication_2_" data-name="icons8-communication (2)" transform="translate(168.001 34)"> |
|||
<path id="Path_47024" data-name="Path 47024" d="M9.5,2A7.488,7.488,0,0,0,2.782,12.82l-.754,3.014a.937.937,0,0,0,1.137,1.137l3.014-.754A7.5,7.5,0,1,0,9.5,2Z" opacity="0.35"/> |
|||
<path id="Path_47025" data-name="Path 47025" d="M20.85,16.35l1.121,4.484a.937.937,0,0,1-1.137,1.137L16.35,20.85Z"/> |
|||
<path id="Path_47026" data-name="Path 47026" d="M16.677,7.323a7.5,7.5,0,0,1-9.354,9.354,7.5,7.5,0,1,0,9.354-9.354Z"/> |
|||
<path id="Path_47027" data-name="Path 47027" d="M13,9H7A1,1,0,0,1,7,7h6a1,1,0,0,1,0,2Z"/> |
|||
<path id="Path_47028" data-name="Path 47028" d="M11,13H7a1,1,0,0,1,0-2h4a1,1,0,0,1,0,2Z"/> |
|||
</g> |
|||
</g> |
|||
</g> |
|||
</svg> |
@ -0,0 +1,21 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"filename" : "exchangeRateButton.svg", |
|||
"idiom" : "universal", |
|||
"scale" : "1x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "2x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "3x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"author" : "xcode", |
|||
"version" : 1 |
|||
} |
|||
} |
@ -0,0 +1,10 @@ |
|||
<svg id="_24px_43_" data-name="24px (43)" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"> |
|||
<path id="Path_1000" data-name="Path 1000" d="M0,0H20V20H0Z" fill="none"/> |
|||
<g id="icons8-up-down-arrow" transform="translate(0.799 1.587)"> |
|||
<path id="Path_38524" data-name="Path 38524" d="M.694,0A.693.693,0,0,0,.2,1.181l3.081,3.11a1,1,0,0,0,1.424,0l3.081-3.11A.693.693,0,0,0,7.3,0Z" transform="translate(10.413 12.022)"/> |
|||
<path id="Path_38525" data-name="Path 38525" d="M3.2,7.19V1.6A1.6,1.6,0,0,0,0,1.6V7.19Z" transform="translate(12.81 5.255)"/> |
|||
<circle id="Ellipse_1881" data-name="Ellipse 1881" cx="1.5" cy="1.5" r="1.5" transform="translate(12.457)"/> |
|||
<path id="Path_38526" data-name="Path 38526" d="M7.787,3.407,4.707.3A1,1,0,0,0,3.283.3L.2,3.407A.693.693,0,0,0,.694,4.588H2.4V9.381a1.6,1.6,0,0,0,3.2,0V4.588H7.3A.693.693,0,0,0,7.787,3.407Z" transform="translate(0 0.217)" opacity="0.35"/> |
|||
<circle id="Ellipse_1882" data-name="Ellipse 1882" cx="1.5" cy="1.5" r="1.5" transform="translate(2.947 13.826)" opacity="0.35"/> |
|||
</g> |
|||
</svg> |
@ -0,0 +1,21 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "1x" |
|||
}, |
|||
{ |
|||
"filename" : "guranteed.svg", |
|||
"idiom" : "universal", |
|||
"scale" : "2x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "3x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"author" : "xcode", |
|||
"version" : 1 |
|||
} |
|||
} |
@ -0,0 +1,11 @@ |
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> |
|||
<g id="Group_10682" data-name="Group 10682" transform="translate(656 827.041) rotate(180)"> |
|||
<rect id="Rectangle_2553" data-name="Rectangle 2553" width="24" height="24" transform="translate(632 803.041)" fill="none"/> |
|||
<g id="icons8-japanese-yen" transform="translate(656 827.041) rotate(180)"> |
|||
<circle id="Ellipse_2033" data-name="Ellipse 2033" cx="10" cy="10" r="10" transform="translate(2 2)" fill="#2e89ff" opacity="0.35"/> |
|||
<path id="Path_47186" data-name="Path 47186" d="M15.5,12h-7a.5.5,0,0,0,0,1h7a.5.5,0,0,0,0-1Z" fill="#2e89ff"/> |
|||
<path id="Path_47187" data-name="Path 47187" d="M15.5,14h-7a.5.5,0,0,0,0,1h7a.5.5,0,0,0,0-1Z" fill="#2e89ff"/> |
|||
<path id="Path_47188" data-name="Path 47188" d="M13.214,13.538V16.28a1.22,1.22,0,0,1-1.22,1.22h0a1.22,1.22,0,0,1-1.22-1.22V13.538L8.636,8.126A1.188,1.188,0,0,1,9.741,6.5h.048a1.19,1.19,0,0,1,1.142.858L12,11.052h.032l1.085-3.7a1.187,1.187,0,0,1,1.14-.854h0a1.189,1.189,0,0,1,1.105,1.628Z" fill="#2e89ff"/> |
|||
</g> |
|||
</g> |
|||
</svg> |
@ -0,0 +1,21 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "1x" |
|||
}, |
|||
{ |
|||
"filename" : "transfer.svg", |
|||
"idiom" : "universal", |
|||
"scale" : "2x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "3x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"author" : "xcode", |
|||
"version" : 1 |
|||
} |
|||
} |
@ -0,0 +1,14 @@ |
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> |
|||
<g id="Group_10682" data-name="Group 10682" transform="translate(656 827.041) rotate(180)"> |
|||
<rect id="Rectangle_2553" data-name="Rectangle 2553" width="24" height="24" transform="translate(632 803.041)" fill="none"/> |
|||
<g id="icons8-stack-of-coins" transform="translate(656 827.041) rotate(180)"> |
|||
<path id="Path_47189" data-name="Path 47189" d="M12,4.5C12,3.119,9.761,2,7,2S2,3.119,2,4.5v15C2,20.881,4.239,22,7,22s5-1.119,5-2.5Z" fill="#2e89ff" opacity="0.35"/> |
|||
<path id="Path_47190" data-name="Path 47190" d="M22,8.5C22,7.119,19.761,6,17,6s-5,1.119-5,2.5v9c0,1.381,2.239,2.5,5,2.5s5-1.119,5-2.5Z" fill="#2e89ff" opacity="0.35"/> |
|||
<path id="Path_47191" data-name="Path 47191" d="M17,17c-2.761,0-5-1.119-5-2.5v3c0,1.381,2.239,2.5,5,2.5s5-1.119,5-2.5v-3C22,15.881,19.761,17,17,17Z" fill="#2e89ff"/> |
|||
<path id="Path_47192" data-name="Path 47192" d="M7,19c-2.761,0-5-1.119-5-2.5v3C2,20.881,4.239,22,7,22s5-1.119,5-2.5v-3C12,17.881,9.761,19,7,19Z" fill="#2e89ff"/> |
|||
<path id="Path_47193" data-name="Path 47193" d="M7,13c-2.761,0-5-1.119-5-2.5v3C2,14.881,4.239,16,7,16s5-1.119,5-2.5v-3C12,11.881,9.761,13,7,13Z" fill="#2e89ff"/> |
|||
<path id="Path_47194" data-name="Path 47194" d="M7,7C4.239,7,2,5.881,2,4.5v3C2,8.881,4.239,10,7,10s5-1.119,5-2.5v-3C12,5.881,9.761,7,7,7Z" fill="#2e89ff"/> |
|||
<path id="Path_47195" data-name="Path 47195" d="M17,11c-2.761,0-5-1.119-5-2.5v3c0,1.381,2.239,2.5,5,2.5s5-1.119,5-2.5v-3C22,9.881,19.761,11,17,11Z" fill="#2e89ff"/> |
|||
</g> |
|||
</g> |
|||
</svg> |
@ -0,0 +1,21 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "1x" |
|||
}, |
|||
{ |
|||
"filename" : "Group 10556.svg", |
|||
"idiom" : "universal", |
|||
"scale" : "2x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "3x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"author" : "xcode", |
|||
"version" : 1 |
|||
} |
|||
} |
@ -0,0 +1,15 @@ |
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> |
|||
<g id="Group_10556" data-name="Group 10556" transform="translate(-320 -39)"> |
|||
<g id="Group_10401" data-name="Group 10401" transform="translate(152 5)"> |
|||
<rect id="Rectangle_2575" data-name="Rectangle 2575" width="24" height="24" transform="translate(168 34)" fill="none"/> |
|||
<g id="icons8-notification" transform="translate(168 33.999)"> |
|||
<path id="Path_46976" data-name="Path 46976" d="M9,20a3,3,0,0,0,6,0Z"/> |
|||
<path id="Path_46977" data-name="Path 46977" d="M19,10.667V9.294A7.194,7.194,0,0,0,12.215,2,7,7,0,0,0,5,9v1.667a7,7,0,0,1-1.4,4.2L2.45,16.4A2.249,2.249,0,0,0,2,17.75H2A2.25,2.25,0,0,0,4.25,20h15.5A2.25,2.25,0,0,0,22,17.75h0a2.249,2.249,0,0,0-.45-1.35L20.4,14.867A7,7,0,0,1,19,10.667Z" opacity="0.35"/> |
|||
</g> |
|||
</g> |
|||
<g id="Group_10402" data-name="Group 10402" transform="translate(318 40)"> |
|||
<circle id="Ellipse_1811" data-name="Ellipse 1811" cx="8" cy="8" r="8" transform="translate(10 -1)"/> |
|||
<text id="_12" data-name="12" transform="translate(13 10)" font-size="10" font-family="Volte-SemiBold, Volte" font-weight="600" letter-spacing="0.013em"><tspan x="0" y="0">12</tspan></text> |
|||
</g> |
|||
</g> |
|||
</svg> |
@ -0,0 +1,21 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "1x" |
|||
}, |
|||
{ |
|||
"filename" : "Group 10401.svg", |
|||
"idiom" : "universal", |
|||
"scale" : "2x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "3x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"author" : "xcode", |
|||
"version" : 1 |
|||
} |
|||
} |
@ -0,0 +1,9 @@ |
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> |
|||
<g id="Group_10401" data-name="Group 10401" transform="translate(-168 -34)"> |
|||
<rect id="Rectangle_2575" data-name="Rectangle 2575" width="24" height="24" transform="translate(168 34)" fill="none"/> |
|||
<g id="icons8-notification" transform="translate(168 33.999)"> |
|||
<path id="Path_46976" data-name="Path 46976" d="M9,20a3,3,0,0,0,6,0Z"/> |
|||
<path id="Path_46977" data-name="Path 46977" d="M19,10.667V9.294A7.194,7.194,0,0,0,12.215,2,7,7,0,0,0,5,9v1.667a7,7,0,0,1-1.4,4.2L2.45,16.4A2.249,2.249,0,0,0,2,17.75H2A2.25,2.25,0,0,0,4.25,20h15.5A2.25,2.25,0,0,0,22,17.75h0a2.249,2.249,0,0,0-.45-1.35L20.4,14.867A7,7,0,0,1,19,10.667Z" opacity="0.35"/> |
|||
</g> |
|||
</g> |
|||
</svg> |
@ -1,6 +1,6 @@ |
|||
{ |
|||
"info" : { |
|||
"version" : 1, |
|||
"author" : "xcode" |
|||
"author" : "xcode", |
|||
"version" : 1 |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,21 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "1x" |
|||
}, |
|||
{ |
|||
"filename" : "style_black_24dp.svg", |
|||
"idiom" : "universal", |
|||
"scale" : "2x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "3x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"author" : "xcode", |
|||
"version" : 1 |
|||
} |
|||
} |
@ -0,0 +1,8 @@ |
|||
<svg id="style_black_24dp" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> |
|||
<path id="Path_43491" data-name="Path 43491" d="M0,0H24V24H0Z" fill="none"/> |
|||
<g id="icons8-contact"> |
|||
<path id="Path_43619" data-name="Path 43619" d="M19,5H11L9.879,3.879A3,3,0,0,0,7.757,3H4A2,2,0,0,0,2,5V18a3,3,0,0,0,3,3H7a1,1,0,0,1,2,0h6a1,1,0,0,1,2,0h2a3,3,0,0,0,3-3V8A3,3,0,0,0,19,5Z" fill="#2e89ff" opacity="0.35"/> |
|||
<circle id="Ellipse_1910" data-name="Ellipse 1910" cx="2" cy="2" r="2" transform="translate(10 8)" fill="#2e89ff"/> |
|||
<path id="Path_43620" data-name="Path 43620" d="M14.5,14h-5a1.5,1.5,0,0,0,0,3h5a1.5,1.5,0,0,0,0-3Z" fill="#2e89ff"/> |
|||
</g> |
|||
</svg> |
@ -0,0 +1,21 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "1x" |
|||
}, |
|||
{ |
|||
"filename" : "style_black_24dp (1).svg", |
|||
"idiom" : "universal", |
|||
"scale" : "2x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "3x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"author" : "xcode", |
|||
"version" : 1 |
|||
} |
|||
} |
@ -0,0 +1,8 @@ |
|||
<svg id="style_black_24dp" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> |
|||
<path id="Path_43491" data-name="Path 43491" d="M0,0H24V24H0Z" fill="none"/> |
|||
<g id="icons8-contact"> |
|||
<path id="Path_43619" data-name="Path 43619" d="M19,5H11L9.879,3.879A3,3,0,0,0,7.757,3H4A2,2,0,0,0,2,5V18a3,3,0,0,0,3,3H7a1,1,0,0,1,2,0h6a1,1,0,0,1,2,0h2a3,3,0,0,0,3-3V8A3,3,0,0,0,19,5Z" opacity="0.35"/> |
|||
<circle id="Ellipse_1910" data-name="Ellipse 1910" cx="2" cy="2" r="2" transform="translate(10 8)"/> |
|||
<path id="Path_43620" data-name="Path 43620" d="M14.5,14h-5a1.5,1.5,0,0,0,0,3h5a1.5,1.5,0,0,0,0-3Z"/> |
|||
</g> |
|||
</svg> |
@ -0,0 +1,21 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "1x" |
|||
}, |
|||
{ |
|||
"filename" : "Group 10878.svg", |
|||
"idiom" : "universal", |
|||
"scale" : "2x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "3x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"author" : "xcode", |
|||
"version" : 1 |
|||
} |
|||
} |
@ -0,0 +1,10 @@ |
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> |
|||
<g id="Group_10878" data-name="Group 10878" transform="translate(-632 -803.041)"> |
|||
<rect id="Rectangle_2553" data-name="Rectangle 2553" width="24" height="24" transform="translate(632 803.041)" fill="none"/> |
|||
<g id="icons8-home-page" transform="translate(631.999 803.543)"> |
|||
<path id="Path_43550" data-name="Path 43550" d="M18,21H6a3,3,0,0,1-3-3V8.765A3,3,0,0,1,4.543,6.143l6-3.333a3,3,0,0,1,2.914,0l6,3.333A3,3,0,0,1,21,8.765V18A3,3,0,0,1,18,21Z" fill="#0052ff" opacity="0.35"/> |
|||
<path id="Path_43551" data-name="Path 43551" d="M15,21H9V15a2,2,0,0,1,2-2h2a2,2,0,0,1,2,2Z" fill="#0052ff"/> |
|||
<path id="Path_43552" data-name="Path 43552" d="M20.5,9.23a1.494,1.494,0,0,1-.727-.189l-6.839-3.8a1.909,1.909,0,0,0-1.864,0L4.23,9.041A1.5,1.5,0,0,1,2.773,6.418l6.839-3.8a4.888,4.888,0,0,1,4.778,0l6.839,3.8A1.5,1.5,0,0,1,20.5,9.23Z" fill="#0052ff"/> |
|||
</g> |
|||
</g> |
|||
</svg> |
@ -0,0 +1,21 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "1x" |
|||
}, |
|||
{ |
|||
"filename" : "Group 10877.svg", |
|||
"idiom" : "universal", |
|||
"scale" : "2x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "3x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"author" : "xcode", |
|||
"version" : 1 |
|||
} |
|||
} |
@ -0,0 +1,10 @@ |
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> |
|||
<g id="Group_10877" data-name="Group 10877" transform="translate(-632 -803.041)"> |
|||
<rect id="Rectangle_2553" data-name="Rectangle 2553" width="24" height="24" transform="translate(632 803.041)" fill="none"/> |
|||
<g id="icons8-home-page" transform="translate(631.999 803.543)"> |
|||
<path id="Path_43550" data-name="Path 43550" d="M18,21H6a3,3,0,0,1-3-3V8.765A3,3,0,0,1,4.543,6.143l6-3.333a3,3,0,0,1,2.914,0l6,3.333A3,3,0,0,1,21,8.765V18A3,3,0,0,1,18,21Z" opacity="0.35"/> |
|||
<path id="Path_43551" data-name="Path 43551" d="M15,21H9V15a2,2,0,0,1,2-2h2a2,2,0,0,1,2,2Z"/> |
|||
<path id="Path_43552" data-name="Path 43552" d="M20.5,9.23a1.494,1.494,0,0,1-.727-.189l-6.839-3.8a1.909,1.909,0,0,0-1.864,0L4.23,9.041A1.5,1.5,0,0,1,2.773,6.418l6.839-3.8a4.888,4.888,0,0,1,4.778,0l6.839,3.8A1.5,1.5,0,0,1,20.5,9.23Z"/> |
|||
</g> |
|||
</g> |
|||
</svg> |
@ -0,0 +1,95 @@ |
|||
// |
|||
// CurrencyTextField.swift |
|||
// WorkingWithCurrencies |
|||
// |
|||
// Created by Josh R on 9/8/20. |
|||
// Copyright © 2020 Josh R. All rights reserved. |
|||
// |
|||
|
|||
import UIKit |
|||
|
|||
class CurrencyTextField: UITextField { |
|||
|
|||
var currencyType: String? |
|||
var passTextFieldText: ((String) -> Void)? |
|||
var keyBoardType: UIKeyboardType = .default |
|||
override init(frame: CGRect) { |
|||
super.init(frame: frame) |
|||
setup() |
|||
} |
|||
|
|||
required init?(coder: NSCoder) { |
|||
super.init(coder: coder) |
|||
//If using in SBs |
|||
setup() |
|||
} |
|||
|
|||
private func setup() { |
|||
self.keyboardType = keyBoardType |
|||
self.contentScaleFactor = 0.5 |
|||
delegate = self |
|||
|
|||
self.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged) |
|||
} |
|||
|
|||
//AFTER entered string is registered in the textField |
|||
@objc private func textFieldDidChange() { |
|||
updateTextField() |
|||
} |
|||
|
|||
//Placed in separate method so when the user selects an account with a different currency, it will immediately be reflected |
|||
private func updateTextField() { |
|||
var cleanedAmount = "" |
|||
for character in self.text ?? "" { |
|||
if character.isNumber { |
|||
cleanedAmount.append(character) |
|||
} |
|||
} |
|||
|
|||
self.text = getCommaLike3DigitMoneytext(cleanedAmount) |
|||
passTextFieldText?(self.text!) |
|||
} |
|||
|
|||
func getCommaLike3DigitMoneytext( _ amount: String) -> String { |
|||
var numberOfArrayOfString: [Character] = [] |
|||
var numbero3DigitsString: [String] = [] |
|||
let textArray = Array(amount) |
|||
for (i, value) in textArray.enumerated() { |
|||
if let lastElement = textArray.elementAt(index:( textArray.count - 1) - i) { |
|||
numberOfArrayOfString.append(lastElement) |
|||
} |
|||
} |
|||
|
|||
var concanetedText = "" |
|||
for (i, value) in numberOfArrayOfString.enumerated() { |
|||
let currentIndex = (textArray.count - 1) - i |
|||
if(currentIndex % 3 != 0) { |
|||
if let text = numberOfArrayOfString.elementAt(index: currentIndex) { |
|||
concanetedText = concanetedText + String(text) |
|||
} |
|||
} else { |
|||
if let text = numberOfArrayOfString.elementAt(index: currentIndex) { |
|||
concanetedText = concanetedText + String(text) |
|||
numbero3DigitsString.append(concanetedText) |
|||
concanetedText = "" |
|||
} |
|||
} |
|||
} |
|||
|
|||
return numbero3DigitsString.joined(separator: ",") |
|||
} |
|||
} |
|||
|
|||
|
|||
extension CurrencyTextField: UITextFieldDelegate { |
|||
|
|||
func textFieldDidEndEditing(_ textField: UITextField) { |
|||
let parsedText = textField.text?.replacingOccurrences(of: currencyType ?? "", with: "") ?? "" |
|||
textField.text = parsedText + (currencyType ?? "") |
|||
} |
|||
|
|||
func textFieldDidBeginEditing(_ textField: UITextField) { |
|||
let parsedText = textField.text?.replacingOccurrences(of: currencyType ?? "", with: "") ?? "" |
|||
textField.text = parsedText |
|||
} |
|||
} |
@ -0,0 +1,130 @@ |
|||
// |
|||
|
|||
import Foundation |
|||
import UIKit |
|||
|
|||
@IBDesignable |
|||
class CustomPageControl: UIControl { |
|||
//MARK:- Properties |
|||
|
|||
private var numberOfDots = [UIView]() { |
|||
didSet{ |
|||
if numberOfDots.count == numberOfPages { |
|||
setupViews() |
|||
} |
|||
} |
|||
} |
|||
|
|||
@IBInspectable var numberOfPages: Int = 0 { |
|||
didSet{ |
|||
|
|||
for tag in 0 ..< numberOfPages { |
|||
let dot = getDotView() |
|||
dot.tag = tag |
|||
dot.backgroundColor = pageIndicatorTintColor |
|||
self.numberOfDots.append(dot) |
|||
} |
|||
} |
|||
} |
|||
|
|||
var currentPage: Int = 0 { |
|||
didSet{ |
|||
onPageControlSwipe() |
|||
} |
|||
} |
|||
|
|||
@IBInspectable var pageIndicatorTintColor: UIColor? = .blue |
|||
@IBInspectable var currentPageIndicatorTintColor: UIColor? = .green |
|||
|
|||
private lazy var stackView = UIStackView.init(frame: self.bounds) |
|||
private lazy var constantSpace = ((stackView.spacing) * CGFloat(numberOfPages - 1) + ((self.bounds.height * 0.45) * CGFloat(numberOfPages)) - self.bounds.width) |
|||
|
|||
|
|||
override var bounds: CGRect { |
|||
didSet{ |
|||
self.numberOfDots.forEach { (dot) in |
|||
self.setupDotAppearance(dot: dot) |
|||
} |
|||
} |
|||
} |
|||
|
|||
//MARK:- Intialisers |
|||
convenience init() { |
|||
self.init(frame: .zero) |
|||
} |
|||
|
|||
init(withNoOfPages pages: Int) { |
|||
self.numberOfPages = pages |
|||
self.currentPage = 0 |
|||
super.init(frame: .zero) |
|||
setupViews() |
|||
} |
|||
|
|||
override init(frame: CGRect) { |
|||
super.init(frame: frame) |
|||
setupViews() |
|||
} |
|||
|
|||
required init?(coder aDecoder: NSCoder) { |
|||
super.init(coder: aDecoder) |
|||
|
|||
} |
|||
private func setupViews() { |
|||
|
|||
self.numberOfDots.forEach { (dot) in |
|||
self.stackView.addArrangedSubview(dot) |
|||
} |
|||
|
|||
stackView.alignment = .center |
|||
stackView.axis = .horizontal |
|||
stackView.distribution = .fillEqually |
|||
stackView.spacing = 8 |
|||
stackView.translatesAutoresizingMaskIntoConstraints = false |
|||
self.addSubview(stackView) |
|||
|
|||
self.addConstraints([ |
|||
stackView.centerXAnchor.constraint(equalTo: self.centerXAnchor), |
|||
stackView.centerYAnchor.constraint(equalTo: self.centerYAnchor), |
|||
stackView.heightAnchor.constraint(equalTo: self.heightAnchor), |
|||
]) |
|||
|
|||
self.numberOfDots.forEach { dot in |
|||
self.addConstraints([ |
|||
dot.centerYAnchor.constraint(equalTo: self.stackView.centerYAnchor), |
|||
dot.widthAnchor.constraint(equalToConstant: 7), |
|||
dot.heightAnchor.constraint(equalToConstant: 7), |
|||
]) |
|||
} |
|||
self.numberOfDots.forEach { dot in |
|||
dot.layer.cornerRadius = dot.bounds.height / 2 |
|||
} |
|||
} |
|||
|
|||
@objc private func onPageControlSwipe() { |
|||
_ = numberOfDots.map { (dot) in |
|||
setupDotAppearance(dot: dot) |
|||
if dot.tag == currentPage { |
|||
UIView.animate(withDuration: 0.2, animations: { |
|||
dot.layer.cornerRadius = dot.bounds.height / 5 |
|||
dot.transform = CGAffineTransform.init(scaleX: 2, y: 1) |
|||
dot.backgroundColor = self.currentPageIndicatorTintColor |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
|
|||
//MARK: Helper methods... |
|||
private func getDotView() -> UIView { |
|||
let dot = UIView() |
|||
self.setupDotAppearance(dot: dot) |
|||
dot.translatesAutoresizingMaskIntoConstraints = false |
|||
return dot |
|||
} |
|||
|
|||
private func setupDotAppearance(dot: UIView) { |
|||
dot.transform = .identity |
|||
dot.layer.cornerRadius = dot.bounds.height / 2 |
|||
dot.layer.masksToBounds = true |
|||
dot.backgroundColor = pageIndicatorTintColor |
|||
} |
|||
} |
@ -0,0 +1,172 @@ |
|||
// |
|||
|
|||
import UIKit |
|||
|
|||
class ExchangeRateCustomView: UIView { |
|||
|
|||
var passTextFieldText: ((String) -> Void)? |
|||
var didSelectCountry: (() -> ())? |
|||
var isReciver: Bool = false |
|||
var text: String? |
|||
var countryListTapGuesture: UITapGestureRecognizer? |
|||
var updatedText: String? { |
|||
didSet { |
|||
updateText() |
|||
} |
|||
} |
|||
|
|||
var currency: String? { |
|||
didSet { |
|||
updateCurrency() |
|||
} |
|||
} |
|||
|
|||
var flag: UIImage? { |
|||
didSet { |
|||
updateFlag() |
|||
} |
|||
} |
|||
|
|||
var title: String? { |
|||
didSet { |
|||
titleLabel.text = title |
|||
} |
|||
} |
|||
|
|||
private var textfield: CurrencyTextField = { |
|||
let textfield = CurrencyTextField() |
|||
textfield.tintColor = .theme2E89FF |
|||
textfield.textColor = .init(hex: "#2E89FF").withAlphaComponent(0.87) |
|||
textfield.font = .sanfrancisco(.semibold, size: 16) |
|||
textfield.translatesAutoresizingMaskIntoConstraints = false |
|||
return textfield |
|||
}() |
|||
|
|||
private var titleLabel: UILabel = { |
|||
let label = UILabel() |
|||
label.font = .sanfrancisco(.semibold, size: 12) |
|||
label.textColor = .themeGray1 |
|||
label.translatesAutoresizingMaskIntoConstraints = false |
|||
return label |
|||
}() |
|||
|
|||
|
|||
var currencyText: UILabel = { |
|||
let text = UILabel() |
|||
text.translatesAutoresizingMaskIntoConstraints = false |
|||
return text |
|||
}() |
|||
|
|||
var flagImageView: UIImageView = { |
|||
let imageView = UIImageView() |
|||
imageView.translatesAutoresizingMaskIntoConstraints = false |
|||
imageView.heightAnchor.constraint(equalToConstant: 40).isActive = true |
|||
imageView.widthAnchor.constraint(equalToConstant: 40).isActive = true |
|||
return imageView |
|||
}() |
|||
|
|||
private var leftStackView: UIStackView! |
|||
private var rightStackView: UIStackView! |
|||
|
|||
init(isReciver: Bool) { |
|||
super.init(frame: .zero) |
|||
self.isReciver = isReciver |
|||
setup() |
|||
} |
|||
|
|||
|
|||
required init?(coder: NSCoder) { |
|||
fatalError("init(coder:) has not been implemented") |
|||
} |
|||
|
|||
private func setup() { |
|||
uiSetup() |
|||
propertiesSetup() |
|||
} |
|||
|
|||
private func uiSetup() { |
|||
leftStackView = UIStackView(arrangedSubviews: [titleLabel, textfield]) |
|||
leftStackView.translatesAutoresizingMaskIntoConstraints = false |
|||
leftStackView.axis = .vertical |
|||
leftStackView.distribution = .fill |
|||
leftStackView.spacing = 4 |
|||
|
|||
rightStackView = UIStackView(arrangedSubviews: [currencyText, |
|||
flagImageView]) |
|||
rightStackView.translatesAutoresizingMaskIntoConstraints = false |
|||
rightStackView.axis = .horizontal |
|||
rightStackView.distribution = .fillEqually |
|||
rightStackView.spacing = 8 |
|||
|
|||
self.addSubviews(leftStackView, |
|||
rightStackView |
|||
) |
|||
|
|||
leftStackView.anchor(top: self.topAnchor, |
|||
paddingTop: isReciver ? 16 : 10, |
|||
bottom: self.bottomAnchor, |
|||
paddingBottom: -13, |
|||
left: self.leadingAnchor, |
|||
paddingLeft: 16 |
|||
) |
|||
|
|||
textfield.passTextFieldText = { [weak self] text in |
|||
self?.text = text |
|||
self?.passTextFieldText?(text) |
|||
} |
|||
|
|||
rightStackView.anchor(right: self.trailingAnchor, |
|||
paddingRight: -8 |
|||
) |
|||
|
|||
rightStackView.center(centerX: nil, |
|||
paddingX: 0, |
|||
centerY: self.centerYAnchor, |
|||
paddingY: 0) |
|||
|
|||
rightStackView.leadingAnchor.constraint(greaterThanOrEqualTo: leftStackView.trailingAnchor, constant: 8).isActive = true |
|||
|
|||
let tap = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:))) |
|||
leftStackView.addGestureRecognizer(tap) |
|||
|
|||
} |
|||
|
|||
private func propertiesSetup() { |
|||
flagImageView.image = UIImage(named: "flag_japan") |
|||
currencyText.text = "JPY" |
|||
currencyText.textColor = .themeBlack |
|||
currencyText.font = .sanfrancisco(.semibold, size: 16) |
|||
|
|||
titleLabel.textColor = .themeBlack.withAlphaComponent(0.6) |
|||
titleLabel.font = .sanfrancisco(.semibold, size: 14) |
|||
|
|||
|
|||
if(isReciver) { |
|||
countryListTapGuesture = UITapGestureRecognizer(target: self, action: #selector(showCurrencyCountryPickerview)) |
|||
rightStackView.addGestureRecognizer(countryListTapGuesture ?? UITapGestureRecognizer()) |
|||
} else { |
|||
countryListTapGuesture = nil |
|||
} |
|||
} |
|||
|
|||
@objc func handleTap(_ sender: UITapGestureRecognizer? = nil) { |
|||
textfield.becomeFirstResponder() |
|||
} |
|||
|
|||
@objc private func showCurrencyCountryPickerview() { |
|||
didSelectCountry?() |
|||
} |
|||
|
|||
private func updateText() { |
|||
textfield.text = updatedText |
|||
} |
|||
|
|||
private func updateCurrency() { |
|||
currencyText.text = currency |
|||
} |
|||
|
|||
private func updateFlag() { |
|||
flagImageView.image = flag |
|||
} |
|||
|
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue