From 2a040808399900a875508b3dc69a7c0cd1479d47 Mon Sep 17 00:00:00 2001 From: Artur Azarau Date: Thu, 7 Feb 2019 20:29:41 +0300 Subject: [PATCH] first concept --- LeadKit.xcodeproj/project.pbxproj | 20 + .../Views/BigBossButton/BigBossButton.swift | 108 +++++ .../BigBossButton/BigBossButtonView.swift | 379 ++++++++++++++++++ .../BigBossButtonViewModel.swift | 53 +++ 4 files changed, 560 insertions(+) create mode 100644 Sources/Classes/Views/BigBossButton/BigBossButton.swift create mode 100644 Sources/Classes/Views/BigBossButton/BigBossButtonView.swift create mode 100644 Sources/Classes/Views/BigBossButton/BigBossButtonViewModel.swift diff --git a/LeadKit.xcodeproj/project.pbxproj b/LeadKit.xcodeproj/project.pbxproj index 8618dc7c..a70176ef 100644 --- a/LeadKit.xcodeproj/project.pbxproj +++ b/LeadKit.xcodeproj/project.pbxproj @@ -665,6 +665,9 @@ 6B5B6EF1577C8CC06E4CCF1B /* Array+RowExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B5B62E7942E5AEE68A95449 /* Array+RowExtensions.swift */; }; 6B5B6F0BFA22832C47142BAD /* TableKitViewModel+Extenstions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B5B61443DDAB82927448CAA /* TableKitViewModel+Extenstions.swift */; }; 6B5B6F4E2B4F6F74348AC138 /* TableKitViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B5B66503F2C42D009DEA011 /* TableKitViewModel.swift */; }; + 72039D172209AF0200875DD4 /* BigBossButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72039D162209AF0200875DD4 /* BigBossButtonView.swift */; }; + 72039D192209D28400875DD4 /* BigBossButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72039D182209D28400875DD4 /* BigBossButton.swift */; }; + 722810B4220C975B00C512CE /* BigBossButtonViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 722810B3220C975B00C512CE /* BigBossButtonViewModel.swift */; }; 7295473F21E661E6009558E7 /* TitleType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7295473E21E661E6009558E7 /* TitleType.swift */; }; 7295474221E6628C009558E7 /* UINavigationItem+Support.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7295474121E6628C009558E7 /* UINavigationItem+Support.swift */; }; 7295474421E66328009558E7 /* UIViewController+UpdateNavigationItemTitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7295474321E66328009558E7 /* UIViewController+UpdateNavigationItemTitle.swift */; }; @@ -985,6 +988,9 @@ 6B5B61443DDAB82927448CAA /* TableKitViewModel+Extenstions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TableKitViewModel+Extenstions.swift"; sourceTree = ""; }; 6B5B62E7942E5AEE68A95449 /* Array+RowExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Array+RowExtensions.swift"; sourceTree = ""; }; 6B5B66503F2C42D009DEA011 /* TableKitViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableKitViewModel.swift; sourceTree = ""; }; + 72039D162209AF0200875DD4 /* BigBossButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BigBossButtonView.swift; sourceTree = ""; }; + 72039D182209D28400875DD4 /* BigBossButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BigBossButton.swift; sourceTree = ""; }; + 722810B3220C975B00C512CE /* BigBossButtonViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BigBossButtonViewModel.swift; sourceTree = ""; }; 7295473E21E661E6009558E7 /* TitleType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleType.swift; sourceTree = ""; }; 7295474121E6628C009558E7 /* UINavigationItem+Support.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationItem+Support.swift"; sourceTree = ""; }; 7295474321E66328009558E7 /* UIViewController+UpdateNavigationItemTitle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+UpdateNavigationItemTitle.swift"; sourceTree = ""; }; @@ -1145,6 +1151,7 @@ 671461D41EB3396E00EAB194 /* Views */ = { isa = PBXGroup; children = ( + 72039D152209AEEC00875DD4 /* BigBossButton */, 677B06B6211873E7006C947D /* BasePlaceholderView */, 67DB77672108714A001CB56B /* CollectionViewWrapperView */, 673CF42A2063DE3A00C329F6 /* DefaultPlaceholders */, @@ -2177,6 +2184,16 @@ path = TableKitViewModel; sourceTree = ""; }; + 72039D152209AEEC00875DD4 /* BigBossButton */ = { + isa = PBXGroup; + children = ( + 72039D162209AF0200875DD4 /* BigBossButtonView.swift */, + 72039D182209D28400875DD4 /* BigBossButton.swift */, + 722810B3220C975B00C512CE /* BigBossButtonViewModel.swift */, + ); + path = BigBossButton; + sourceTree = ""; + }; 78CFEE201C5C456B00F50370 = { isa = PBXGroup; children = ( @@ -2901,6 +2918,7 @@ EFBE57D01EC35EF20040E00A /* Array+Extensions.swift in Sources */, 6792623C206EB0EC00308E62 /* CellSeparatorType+Extensions.swift in Sources */, 671462E41EB3396E00EAB194 /* UIColor+Hex.swift in Sources */, + 722810B4220C975B00C512CE /* BigBossButtonViewModel.swift in Sources */, 67EB7FF12061682F00BDD9FB /* TotalCountCursorListingResult+DefaultTotalCountCursorListingResult.swift in Sources */, 67EB8001206177D600BDD9FB /* PaginationWrapperDelegate.swift in Sources */, 67FD4382206BD24B005B0C64 /* EqutableOptionalArray.swift in Sources */, @@ -2954,6 +2972,7 @@ 67A1FF941EBCA65E00D6C89F /* CABasicAnimation+Rotation.swift in Sources */, 82F8BB181F5DDED100C1061B /* Single+DeferredJust.swift in Sources */, 671463301EB3396E00EAB194 /* CursorType.swift in Sources */, + 72039D192209D28400875DD4 /* BigBossButton.swift in Sources */, 67FDC25F1FA310EA00C76A77 /* RequestError.swift in Sources */, 677B06A021186A69006C947D /* SharedSequence+Extensions.swift in Sources */, 6760DC4D212F351700020BAE /* UIView+AddSubviews.swift in Sources */, @@ -3068,6 +3087,7 @@ 6714628C1EB3396E00EAB194 /* CGImage+Alpha.swift in Sources */, 671462741EB3396E00EAB194 /* LeadKitError.swift in Sources */, 677452A420625FA90024EEEF /* RxDataSource.swift in Sources */, + 72039D172209AF0200875DD4 /* BigBossButtonView.swift in Sources */, 820CAD8420B43B080033EF94 /* PaginationWrapperDelegate+DefaultImplementation.swift in Sources */, 671AD262206A35EC00EAF887 /* UIApplication+Cellular.swift in Sources */, 6713C23C20AF0D5900875921 /* NetworkOperationModel.swift in Sources */, diff --git a/Sources/Classes/Views/BigBossButton/BigBossButton.swift b/Sources/Classes/Views/BigBossButton/BigBossButton.swift new file mode 100644 index 00000000..820cb63d --- /dev/null +++ b/Sources/Classes/Views/BigBossButton/BigBossButton.swift @@ -0,0 +1,108 @@ +// +// Copyright (c) 2019 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import UIKit +import RxCocoa +import RxSwift + +open class BigBossButton: UIButton { + + // MARK: - Constants + + private let defaultBackgroundColor = UIColor.white + + // MARK: - Background + + private var backgroundColors: [UIControl.State: UIColor] = [:] { + didSet { + updateBackgroundColor() + } + } + + func set(backgroundColors: [UIControl.State: UIColor]) { + backgroundColors.forEach { setBackgroundColor($1, for: $0) } + } + + func setBackgroundColor(_ color: UIColor, for state: UIControl.State) { + backgroundColors[state] = color + } + + func backgroundColor(for state: UIControl.State) -> UIColor? { + return backgroundColors[state] + } + + private func updateBackgroundColor() { + if isEnabled { + if isHighlighted { + updateBackgroundColor(to: .highlighted) + } else { + updateBackgroundColor(to: .normal) + } + } else { + updateBackgroundColor(to: .disabled) + } + } + + private func updateBackgroundColor(to state: UIControl.State) { + if let stateColor = backgroundColor(for: state) { + backgroundColor = stateColor + } else if state != .normal, let normalStateColor = backgroundColor(for: .normal) { + backgroundColor = normalStateColor + } else { + backgroundColor = defaultBackgroundColor + } + } + + // MARK: - Title + + func set(titleColors: [UIControl.State: UIColor]) { + titleColors.forEach { setTitleColor($1, for: $0) } + } + + func set(titles: [UIControl.State: String]) { + titles.forEach { setTitle($1, for: $0) } + } + + func set(attributtedTitles: [UIControl.State: NSAttributedString]) { + attributtedTitles.forEach { setAttributedTitle($1, for: $0) } + } + + // MARK: - Images + + func set(images: [UIControl.State: UIImage]) { + images.forEach { setImage($1, for: $0) } + } + + // MARK: - State + + override open var isEnabled: Bool { + didSet { + updateBackgroundColor() + } + } + + override open var isHighlighted: Bool { + didSet { + updateBackgroundColor() + } + } +} diff --git a/Sources/Classes/Views/BigBossButton/BigBossButtonView.swift b/Sources/Classes/Views/BigBossButton/BigBossButtonView.swift new file mode 100644 index 00000000..feef1ec3 --- /dev/null +++ b/Sources/Classes/Views/BigBossButton/BigBossButtonView.swift @@ -0,0 +1,379 @@ +// +// Copyright (c) 2019 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import RxSwift +import RxCocoa + +public typealias Spinner = UIView & Animatable + +public struct BigBossButtonState: OptionSet { + + public let rawValue: Int + + public init(rawValue: Int) { + self.rawValue = rawValue + } + + static let highlighted = BigBossButtonState(rawValue: 1 << 1) + static let unhighlighted = BigBossButtonState(rawValue: 1 << 2) + static let enabled = BigBossButtonState(rawValue: 1 << 3) + static let disabled = BigBossButtonState(rawValue: 1 << 4) + + static let loading = BigBossButtonState(rawValue: 1 << 5) + + var isLoading: Bool { + return self.contains(.loading) + } +} + +open class BigBossButtonView: UIView { + + private let disposeBag = DisposeBag() + + override open func touchesBegan(_ touches: Set, with event: UIEvent?) { + if var touchPoint = touches.first?.location(in: self) { + touchPoint = convert(touchPoint, to: self) + if button.frame.contains(touchPoint) && !button.isEnabled { + tapOnDisabledButton?() + } + } + super.touchesBegan(touches, with: event) + } + + // MARK: - Stored Properties + + public var spinnerView: Spinner? { + willSet { + if newValue == nil { + removeSpinner() + } + } + + didSet { + if spinnerView != nil { + addSpinner() + } + } + } + + private let button = BigBossButton() + + public var shadowView = UIView() { + willSet { + shadowView.removeFromSuperview() + } + didSet { + insertSubview(shadowView, at: 0) + configureShadowViewConstraints() + } + } + + private var isEnabledObserver: NSKeyValueObservation? + private var isHighlightedObserver: NSKeyValueObservation? + + public var tapOnDisabledButton: VoidBlock? + + public var appearance = Appearance() { + didSet { + configureAppearance() + configureConstraints() + } + } + + // MARK: - Initialization + + override public init(frame: CGRect) { + super.init(frame: frame) + initializeView() + } + + required public init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + initializeView() + } + + // MARK: - Drivers + + open var tapObservable: Observable { + return button.rx.tap.asObservable() + } + + // MARK: - Button State Observation + + // private func observeIsEnabled() -> NSKeyValueObservation { + // return button.observe(\BigBossButton.isEnabled, options: .new) { [weak self] _, isEnabled in + // + // guard let self = self else { + // return + // } + // + // if let isEnabled = isEnabled.newValue { + // var state = self.stateRelay.value + // state.subtract([.enabled, .disabled]) + // state.insert(isEnabled ? .enabled : .disabled) + // self.stateRelay.accept(state) + // } + // } + // } + // + // private func observeIsHighlighted() -> NSKeyValueObservation { + // return button.observe(\BigBossButton.isHighlighted, options: .new, + // changeHandler: { [weak self] _, isHighlighted in + // + // guard let self = self else { + // return + // } + // + // if let isHighlighted = isHighlighted.newValue { + // var state = self.stateRelay.value + // state.subtract([.highlighted, .unhighlighted]) + // state.insert(isHighlighted ? .highlighted : .unhighlighted) + // self.stateRelay.accept(state) + // } + // }) + // } + + // MARK: - UI + + override open func layoutSubviews() { + super.layoutSubviews() + shadowView.layer.shadowPath = UIBezierPath(rect: button.bounds).cgPath + } + + public var buttonIsDisabledWhileLoading = false + + private func set(active: Bool) { + button.isEnabled = buttonIsDisabledWhileLoading ? !active : true + if active { + spinnerView?.isHidden = false + spinnerView?.startAnimating() + } else { + spinnerView?.isHidden = true + spinnerView?.stopAnimating() + } + } + + private func addSpinner() { + if let spinner = spinnerView { + addSubview(spinner) + configureSpinnerConstraints() + } + } + + private func removeSpinner() { + if spinnerView != nil { + self.spinnerView?.removeFromSuperview() + self.spinnerView = nil + } + } + + // MARK: - Layout + + override open var forFirstBaselineLayout: UIView { + return button.forFirstBaselineLayout + } + + override open var forLastBaselineLayout: UIView { + return button.forLastBaselineLayout + } + + private func configureConstraints() { + button.constaintToEdges(of: self, with: appearance.buttonInsets) + configureShadowViewConstraints() + } + + private func configureSpinnerConstraints() { + switch appearance.spinnerPosition { + case .center: + spinnerView?.centerXAnchor.constraint(equalTo: button.centerXAnchor).isActive = true + spinnerView?.centerYAnchor.constraint(equalTo: button.centerYAnchor).isActive = true + case .leftToText(let offset): + if let buttonLabel = button.titleLabel { + spinnerView?.centerYAnchor.constraint(equalTo: buttonLabel.centerYAnchor).isActive = true + spinnerView?.trailingAnchor.constraint(equalTo: buttonLabel.leadingAnchor, + constant: -offset).isActive = true + } + case .rightToText(let offset): + if let buttonLabel = button.titleLabel { + spinnerView?.centerYAnchor.constraint(equalTo: buttonLabel.centerYAnchor).isActive = true + spinnerView?.leadingAnchor.constraint(equalTo: buttonLabel.trailingAnchor, + constant: offset).isActive = true + } + } + } + + private func configureShadowViewConstraints() { + shadowView.constaintToEdges(of: button, with: .zero) + } +} + +private extension UIView { + func constaintToEdges(of view: UIView, with offset: UIEdgeInsets) { + self.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: offset.left).isActive = true + self.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: offset.right).isActive = true + self.topAnchor.constraint(equalTo: view.topAnchor, constant: offset.top).isActive = true + self.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: offset.bottom).isActive = true + } +} + +extension BigBossButtonView: InitializableView { + + public func addViews() { + addSubviews(shadowView, button) + } + + public func configureAppearance() { + button.titleLabel?.font = appearance.buttonFont + + button.set(titles: appearance.buttonStateTitles) + button.set(attributtedTitles: appearance.buttonStateAttributtedTitles) + button.set(titleColors: appearance.buttonTitleStateColors) + button.set(images: appearance.buttonStateIcons) + button.set(backgroundColors: appearance.buttonBackgroundStateColors) + + let offset = appearance.buttonIconOffset + button.imageEdgeInsets = UIEdgeInsets(top: offset.vertical, + left: offset.horizontal, + bottom: -offset.vertical, + right: -offset.horizontal) + + if let cornerRadius = appearance.buttonCornerRadius { + button.layer.cornerRadius = cornerRadius + } + } +} + +extension BigBossButtonView: ConfigurableView { + public func configure(with viewModel: BigBossButtonViewModel) { + button.titleLabel?.numberOfLines = 0 + viewModel.stateObservable + .skip(1) + .do(onNext: { [weak self] state in + self?.configureButton(withState: state) + self?.onStateChange(state) + }) + .subscribe() + .disposed(by: disposeBag) + + viewModel + .bind(tapObservable: tapObservable) + .disposed(by: disposeBag) + + appearance = viewModel.appearance + } + + open func onStateChange(_ state: BigBossButtonState) { + + } + + open func configureButton(withState state: BigBossButtonState) { + if state.contains(.enabled) { + button.isEnabled = true + } + + if state.contains(.disabled) { + button.isEnabled = false + } + + if state.contains(.highlighted) { + button.isHighlighted = true + } + + if state.contains(.unhighlighted) { + button.isHighlighted = false + } + + if state.contains(.loading) { + set(active: true) + } else { + set(active: false) + } + } +} + +public extension BigBossButtonView { + struct Appearance { + + var buttonFont: UIFont + + var buttonStateTitles: [UIControl.State: String] + var buttonStateAttributtedTitles: [UIControl.State: NSAttributedString] + var buttonTitleStateColors: [UIControl.State: UIColor] + var buttonBackgroundStateColors: [UIControl.State: UIColor] + var buttonStateIcons: [UIControl.State: UIImage] + + var buttonIconOffset: UIOffset + var buttonInsets: UIEdgeInsets + + var buttonHeight: CGFloat + var buttonCornerRadius: CGFloat? + + var buttonShadowPadding: CGFloat + var spinnerPosition: SpinnerPosition + + init(buttonFont: UIFont = .systemFont(ofSize: 15), + buttonStateTitles: [UIControl.State: String] = [:], + buttonStateAttributtedTitles: [UIControl.State: NSAttributedString] = [:], + buttonTitleStateColors: [UIControl.State: UIColor] = [:], + buttonBackgroundStateColors: [UIControl.State: UIColor] = [:], + buttonStateIcons: [UIControl.State: UIImage] = [:], + buttonIconOffset: UIOffset = .zero, + buttonInsets: UIEdgeInsets = .zero, + buttonHeight: CGFloat = 50, + buttonCornerRadius: CGFloat? = nil, + buttonShadowPadding: CGFloat = 0, + spinnerPosition: SpinnerPosition = .center + ) { + + self.buttonFont = buttonFont + + self.buttonStateTitles = buttonStateTitles + self.buttonStateAttributtedTitles = buttonStateAttributtedTitles + self.buttonTitleStateColors = buttonTitleStateColors + self.buttonBackgroundStateColors = buttonBackgroundStateColors + self.buttonStateIcons = buttonStateIcons + + self.buttonIconOffset = buttonIconOffset + self.buttonInsets = buttonInsets + + self.buttonHeight = buttonHeight + self.buttonCornerRadius = buttonCornerRadius + + self.buttonShadowPadding = buttonShadowPadding + self.spinnerPosition = spinnerPosition + } + + } + + enum SpinnerPosition { + case center + case leftToText(offset: CGFloat) + case rightToText(offset: CGFloat) + } +} + +extension UIControl.State: Hashable { + //swiftlint:disable:next - inout_keyword + public func hash(into hasher: inout Hasher) { + hasher.combine(Int(rawValue)) + } +} diff --git a/Sources/Classes/Views/BigBossButton/BigBossButtonViewModel.swift b/Sources/Classes/Views/BigBossButton/BigBossButtonViewModel.swift new file mode 100644 index 00000000..13961811 --- /dev/null +++ b/Sources/Classes/Views/BigBossButton/BigBossButtonViewModel.swift @@ -0,0 +1,53 @@ +// +// Copyright (c) 2019 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import RxCocoa +import RxSwift + +open class BigBossButtonViewModel { + + public typealias Appearance = BigBossButtonView.Appearance + + private let stateRelay = BehaviorRelay(value: BigBossButtonState.enabled) + private let tapRelay = BehaviorRelay(value: ()) + public let appearance: Appearance + + public init(appearance: Appearance) { + self.appearance = appearance + } + + open var stateObservable: Observable { + return stateRelay.asObservable() + } + + func bind(tapObservable: Observable) -> Disposable { + return tapObservable.bind(to: tapRelay) + } + + var tapDriver: Driver { + return tapRelay.asDriver() + } + + func updateState(with newState: BigBossButtonState) { + stateRelay.accept(newState) + } +}