Skip to content
Snippets Groups Projects
Commit 6c74ba6c authored by Bruno Muniz's avatar Bruno Muniz :apple:
Browse files

Fix nickname drawer dependency

parent 840e3905
Branches
No related tags found
1 merge request!97Fix nickname drawer dependency
......@@ -110,6 +110,9 @@ extension NavigatorKey: DependencyKey {
PresentOnboardingEmailNavigator(
OnboardingEmailController.init
),
PresentNicknameNavigator(
NicknameController.init(_:_:)
),
PresentOnboardingSuccessNavigator(
OnboardingSuccessController.init(_:)
),
......
......@@ -8,7 +8,7 @@ public struct PresentNickname: Action {
/// - parent: Parent view controller from which presentation should happen
/// - animated: Animate the transition
public init(
prefilled: String?,
prefilled: String,
completion: @escaping (String) -> Void,
from parent: UIViewController,
animated: Bool = true
......@@ -19,8 +19,8 @@ public struct PresentNickname: Action {
self.animated = animated
}
/// Optional value to be set as placeholder/pre-existent text
public var prefilled: String?
/// Value to be set as placeholder/pre-existent text
public var prefilled: String
/// Closure that passes the value of the text set
public var completion: (String) -> Void
......@@ -38,16 +38,19 @@ public struct PresentNicknameNavigator: TypedNavigator {
let transitioningDelegate = BottomTransitioningDelegate()
/// View controller which should be opened up
var viewController: () -> UIViewController
var viewController: (String, @escaping (String) -> Void) -> UIViewController
/// - Parameters:
/// - viewController: view controller which should be presented
public init(_ viewController: @escaping () -> UIViewController) {
public init(_ viewController: @escaping (
String, @escaping (String) -> Void
) -> UIViewController
) {
self.viewController = viewController
}
public func perform(_ action: PresentNickname, completion: @escaping () -> Void) {
let controller = viewController()
let controller = viewController(action.prefilled, action.completion)
controller.transitioningDelegate = transitioningDelegate
controller.modalPresentationStyle = .overFullScreen
......
import UIKit
import Shared
import Combine
import InputField
import ScrollViewController
public final class NicknameController: UIViewController {
private lazy var screenView = NicknameView()
private let prefilled: String
private let viewModel: NicknameViewModel
private let completion: (String) -> Void
private let viewModel = NicknameViewModel()
private var cancellables = Set<AnyCancellable>()
private let keyboardListener = KeyboardFrameChangeListener(notificationCenter: .default)
public init(_ prefilled: String, _ completion: @escaping (String) -> Void) {
self.prefilled = prefilled
public init(
_ prefilled: String,
_ completion: @escaping (String) -> Void
) {
self.completion = completion
self.viewModel = .init(prefilled: prefilled)
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) { nil }
public override func loadView() {
let view = UIView()
view.addSubview(screenView)
screenView.snp.makeConstraints {
$0.top.equalToSuperview()
$0.left.equalToSuperview()
$0.right.equalToSuperview()
$0.bottom.equalToSuperview().offset(0)
}
self.view = view
view = screenView
}
public override func viewDidLoad() {
super.viewDidLoad()
setupKeyboard()
setupBindings()
screenView.inputField.update(content: prefilled)
viewModel.didInput(prefilled)
}
private func setupKeyboard() {
keyboardListener.keyboardFrameWillChange = { [weak self] keyboard in
guard let self else { return }
let inset = self.view.frame.height - self.view.convert(keyboard.frame, from: nil).minY
self.screenView.snp.updateConstraints {
$0.bottom.equalToSuperview().offset(-inset)
}
self.view.setNeedsLayout()
viewModel
.statePublisher
.removeDuplicates()
.receive(on: DispatchQueue.main)
.sink { [unowned self] in
screenView.inputField.update(status: $0.status)
screenView.inputField.update(content: $0.input)
UIView.animate(withDuration: keyboard.animationDuration) {
self.view.layoutIfNeeded()
}
}
if case .valid = $0.status {
screenView.saveButton.isEnabled = true
} else {
screenView.saveButton.isEnabled = false
}
}.store(in: &cancellables)
private func setupBindings() {
viewModel.state
.map(\.status)
.receive(on: DispatchQueue.main)
.sink { [weak screenView] in screenView?.update(status: $0) }
.store(in: &cancellables)
screenView
.inputField
.textPublisher
.sink { [unowned self] in
viewModel.didInput($0)
}.store(in: &cancellables)
viewModel.done
.receive(on: DispatchQueue.main)
screenView
.saveButton
.publisher(for: .touchUpInside)
.sink { [unowned self] in
dismiss(animated: true)
completion($0)
completion(viewModel.getInput())
}.store(in: &cancellables)
screenView.inputField.textPublisher
.sink { [weak viewModel] in viewModel?.didInput($0) }
.store(in: &cancellables)
screenView.saveButton.publisher(for: .touchUpInside)
.sink { [weak viewModel] in viewModel?.didTapSave() }
.store(in: &cancellables)
}
}
import Shared
import Combine
import InputField
import AppResources
struct NicknameViewState {
var nickname: String = ""
var status: InputField.ValidationStatus = .unknown(nil)
}
final class NicknameViewModel {
// MARK: Properties
var state: AnyPublisher<NicknameViewState, Never> {
stateRelay.eraseToAnyPublisher()
struct ViewState: Equatable {
var input: String
var status: InputField.ValidationStatus
}
var done: AnyPublisher<String, Never> {
doneRelay.eraseToAnyPublisher()
var statePublisher: AnyPublisher<ViewState, Never> {
stateSubject.eraseToAnyPublisher()
}
private let doneRelay = PassthroughSubject<String, Never>()
private let stateRelay = CurrentValueSubject<NicknameViewState, Never>(.init())
// MARK: Public
private let stateSubject: CurrentValueSubject<ViewState, Never>
func didInput(_ string: String) {
stateRelay.value.nickname = string
validate()
init(prefilled: String) {
self.stateSubject = .init(.init(
input: prefilled,
status: .valid(nil)
))
}
func didTapSave() {
doneRelay.send(stateRelay.value.nickname.trimmingCharacters(in: .whitespacesAndNewlines))
func getInput() -> String {
stateSubject.value.input
}
// MARK: Private
func didInput(_ string: String) {
let input = stateSubject.value.input
.trimmingCharacters(in: .whitespacesAndNewlines)
private func validate() {
if stateRelay.value.nickname.trimmingCharacters(in: .whitespacesAndNewlines).count >= 1 {
stateRelay.value.status = .valid(nil)
} else {
stateRelay.value.status = .invalid(Localized.Contact.Nickname.minimum)
}
stateSubject.value.input = input
stateSubject.value.status = input.count >= 1 ?
.valid(nil) :
.invalid(Localized.Contact.Nickname.minimum)
}
}
......@@ -54,15 +54,4 @@ final class NicknameView: UIView {
}
required init?(coder: NSCoder) { nil }
func update(status: InputField.ValidationStatus) {
inputField.update(status: status)
switch status {
case .valid:
saveButton.isEnabled = true
case .invalid, .unknown:
saveButton.isEnabled = false
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment