refactor: notifications and settings view models; enhance login and registration UI
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
struct OTPDigitField: UIViewRepresentable {
|
||||
@Binding var text: String
|
||||
let isFocused: Bool
|
||||
let onFocus: () -> Void
|
||||
let onInsert: () -> Void
|
||||
let onDeleteWhenEmpty: () -> Void
|
||||
let onPaste: ([String]) -> Void
|
||||
|
||||
func makeUIView(context: Context) -> BackspaceAwareTextField {
|
||||
let textField = BackspaceAwareTextField()
|
||||
textField.delegate = context.coordinator
|
||||
textField.keyboardType = .numberPad
|
||||
textField.textAlignment = .center
|
||||
textField.font = UIFont.systemFont(ofSize: 24, weight: .bold)
|
||||
textField.textContentType = .oneTimeCode
|
||||
textField.onDeleteWhenEmpty = {
|
||||
onDeleteWhenEmpty()
|
||||
}
|
||||
textField.addTarget(context.coordinator, action: #selector(Coordinator.editingChanged(_:)), for: .editingChanged)
|
||||
return textField
|
||||
}
|
||||
|
||||
func updateUIView(_ uiView: BackspaceAwareTextField, context: Context) {
|
||||
if uiView.text != text {
|
||||
uiView.text = text
|
||||
}
|
||||
|
||||
if isFocused && !uiView.isFirstResponder {
|
||||
DispatchQueue.main.async {
|
||||
uiView.becomeFirstResponder()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func makeCoordinator() -> Coordinator {
|
||||
Coordinator(parent: self)
|
||||
}
|
||||
|
||||
final class Coordinator: NSObject, UITextFieldDelegate {
|
||||
var parent: OTPDigitField
|
||||
|
||||
init(parent: OTPDigitField) {
|
||||
self.parent = parent
|
||||
}
|
||||
|
||||
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
|
||||
parent.onFocus()
|
||||
return true
|
||||
}
|
||||
|
||||
func textFieldDidBeginEditing(_ textField: UITextField) {
|
||||
parent.onFocus()
|
||||
}
|
||||
|
||||
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
|
||||
if string.isEmpty {
|
||||
return true
|
||||
}
|
||||
|
||||
let digits = string.filter { $0.isNumber }
|
||||
guard !digits.isEmpty else {
|
||||
return false
|
||||
}
|
||||
|
||||
if digits.count > 1 {
|
||||
parent.onPaste(digits.map(String.init))
|
||||
return false
|
||||
}
|
||||
|
||||
parent.text = String(digits.prefix(1))
|
||||
parent.onInsert()
|
||||
return false
|
||||
}
|
||||
|
||||
@objc
|
||||
func editingChanged(_ textField: UITextField) {
|
||||
let digitsOnly = (textField.text ?? "").filter { $0.isNumber }
|
||||
let single = String(digitsOnly.prefix(1))
|
||||
if textField.text != single {
|
||||
textField.text = single
|
||||
}
|
||||
parent.text = single
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class BackspaceAwareTextField: UITextField {
|
||||
var onDeleteWhenEmpty: (() -> Void)?
|
||||
|
||||
override func deleteBackward() {
|
||||
let wasEmpty = (text ?? "").isEmpty
|
||||
super.deleteBackward()
|
||||
if wasEmpty {
|
||||
onDeleteWhenEmpty?()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user