Newer
Older
enum Action {
case info
case addEmail
case addPhone
case toggleEmail
case togglePhone
}
private var isExpanded = false {
didSet { updateBottomConstraint() }
}
private let upperView = UIView()
private let lowerView = UIView()
private var bottomConstraint: Constraint?
private let imageView = UIImageView()
private let titleView = TextWithInfoView()
private let emailView = AttributeSwitcher()
private let phoneView = AttributeSwitcher()
private var cancellables = Set<AnyCancellable>()
private var currentConstraintConstant: CGFloat = 0.0 {
didSet { bottomConstraint?.update(offset: currentConstraintConstant) }
}
private var bottomConstraintExpanded: CGFloat {
-lowerView.frame.height
}
private var bottomConstraintNotExpanded: CGFloat {
0
}
var actionPublisher: AnyPublisher<Action, Never> {
actionSubject.eraseToAnyPublisher()
}
private let actionSubject = PassthroughSubject<Action, Never>()
upperView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(didPan(_:))))
lowerView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(didPan(_:))))
layer.cornerRadius = 30
imageView.image = Asset.scanDropdown.image
clipsToBounds = true
layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
addSubview(upperView)
addSubview(lowerView)
upperView.addSubview(imageView)
upperView.addSubview(titleView)
lowerView.addSubview(emailView)
lowerView.addSubview(phoneView)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakMode = .byWordWrapping
text: Localized.Scan.Display.Share.title,
attributes: [
.foregroundColor: Asset.neutralBody.color,
.font: Fonts.Mulish.regular.font(size: 16.0) as Any,
.paragraphStyle: paragraphStyle
],
didTapInfo: { [weak self] in self?.actionSubject.send(.info) }
emailView.switcherView
.publisher(for: .valueChanged)
.sink { [unowned self] in actionSubject.send(.toggleEmail) }
.store(in: &cancellables)
phoneView.switcherView
.publisher(for: .valueChanged)
.sink { [unowned self] in actionSubject.send(.togglePhone) }
.store(in: &cancellables)
emailView.addButton
.publisher(for: .touchUpInside)
.sink { [unowned self] in actionSubject.send(.addEmail) }
.store(in: &cancellables)
phoneView.addButton
.publisher(for: .touchUpInside)
.sink { [unowned self] in actionSubject.send(.addPhone) }
.store(in: &cancellables)
emailView.setup(state: nil, title: Localized.Scan.Display.Share.email)
phoneView.setup(state: nil, title: Localized.Scan.Display.Share.phone)
emailView.alpha = 0.0
phoneView.alpha = 0.0
imageView.snp.makeConstraints {
$0.top.equalToSuperview().offset(15)
$0.centerX.equalToSuperview()
}
titleView.snp.makeConstraints {
$0.top.equalTo(imageView.snp.bottom).offset(10)
$0.left.equalToSuperview().offset(40)
$0.right.lessThanOrEqualToSuperview().offset(-40)
$0.centerY.equalToSuperview()
}
emailView.snp.makeConstraints {
$0.top.equalToSuperview()
$0.left.equalToSuperview().offset(40)
$0.right.equalToSuperview().offset(-40)
phoneView.snp.makeConstraints {
$0.top.equalTo(emailView.snp.bottom).offset(25)
$0.left.equalToSuperview().offset(40)
$0.right.equalToSuperview().offset(-40)
$0.bottom.equalToSuperview().offset(-40)
upperView.snp.makeConstraints {
$0.top.equalToSuperview()
$0.left.equalToSuperview()
$0.right.equalToSuperview()
bottomConstraint = $0.bottom
.equalTo(safeAreaLayoutGuide)
.constraint
}
lowerView.snp.makeConstraints {
$0.top.equalTo(upperView.snp.bottom).offset(-30)
$0.left.equalToSuperview()
$0.right.equalToSuperview()
}
}
func setup(email state: AttributeSwitcher.State?) {
emailView.setup(state: state, title: Localized.Scan.Display.Share.email)
func setup(phone state: AttributeSwitcher.State?) {
phoneView.setup(state: state, title: Localized.Scan.Display.Share.phone)
}
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
@objc private func didPan(_ sender: UIPanGestureRecognizer) {
switch sender.state {
case .began, .changed:
let isUpwards = sender.translation(in: self).y < 0
let result = currentConstraintConstant + sender.translation(in: self).y
if isUpwards {
currentConstraintConstant = max(bottomConstraintExpanded, result)
} else {
currentConstraintConstant = min(bottomConstraintNotExpanded, result)
}
let currentMinusExpanded = currentConstraintConstant - bottomConstraintExpanded
let notExpandedMinusExpanded = bottomConstraintNotExpanded - bottomConstraintExpanded
let alpha = 1 - (currentMinusExpanded / abs(notExpandedMinusExpanded))
emailView.alpha = alpha
phoneView.alpha = alpha
case .cancelled, .ended, .failed:
let currentMinusExpanded = currentConstraintConstant - bottomConstraintExpanded
let notExpandedMinusExpanded = bottomConstraintNotExpanded - bottomConstraintExpanded
let percentage = currentMinusExpanded / abs(notExpandedMinusExpanded)
isExpanded = percentage < 0.5
case .possible:
break
@unknown default:
break
}
}
private func updateBottomConstraint() {
if isExpanded {
emailView.alpha = 1.0
phoneView.alpha = 1.0
currentConstraintConstant = bottomConstraintExpanded
} else {
emailView.alpha = 0.0
phoneView.alpha = 0.0
currentConstraintConstant = bottomConstraintNotExpanded
}