// // TestToggle.swift // JSONCreator // // Created by Matt Bruce on 10/21/22. // Copyright © 2022 Verizon Wireless. All rights reserved. // import Foundation import MVMCore import MVMCoreUI import UIKit import VDS /** A custom implementation of Apple's UISwitch. By default this class begins in the off state. Container: The background of the toggle control. Knob: The circular indicator that slides on the container. */ open class TestToggle: ToggleBase, VDSMoleculeViewProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- public var viewModel: TestToggleModel! public var delegateObject: MVMCoreUIDelegateObject? public var additionalData: [AnyHashable: Any]? //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- public override func initialSetup() { super.initialSetup() publisher(for: .touchUpInside) .sink {[weak self] toggle in guard let self = self else { return } self.toggle() }.store(in: &subscribers) publisher(for: .valueChanged) .sink {[weak self] toggle in guard let self = self else { return } self.valueChanged(isOn: toggle.isOn) }.store(in: &subscribers) accessibilityLabelEnabled = MVMCoreUIUtility.hardcodedString(withKey: "Toggle_buttonlabel") accessibilityLabelDisabled = MVMCoreUIUtility.hardcodedString(withKey: "Toggle_buttonlabel") accessibilityHintEnabled = MVMCoreUIUtility.hardcodedString(withKey: "AccToggleHint") accessibilityHintDisabled = MVMCoreUIUtility.hardcodedString(withKey: "AccDisabled") accessibilityValueEnabled = MVMCoreUIUtility.hardcodedString(withKey: "AccOn") accessibilityValueDisabled = MVMCoreUIUtility.hardcodedString(withKey: "AccOff") } // MARK:- MVMCoreViewProtocol open func updateView(_ size: CGFloat) {} open func viewModelDidUpdate() { guard let viewModel else { return } additionalData = additionalData.dictionaryAdding(key: KeySourceModel, value: viewModel) } private func valueChanged(isOn: Bool){ guard let viewModel else { return } //sync the value on the viewModel viewModel.selected = isOn //tell the form you changed _ = FormValidator.validate(delegate: self.delegateObject?.formHolderDelegate) if viewModel.action != nil || viewModel.alternateAction != nil { var action: ActionModelProtocol? if isOn { action = viewModel.action } else { action = viewModel.alternateAction ?? viewModel.action } if let action { MVMCoreUIActionHandler.performActionUnstructured(with: action, sourceModel: viewModel, additionalData: additionalData, delegateObject: delegateObject) } } print("toggle value changed to: \(isOn)") print("viewModel server value: \(viewModel.formFieldServerValue()!)") } public static func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { return 44 } private typealias ActionDefinition = (model: ActionModelProtocol, sourceModel: MoleculeModelProtocol?) private func performActionUnstructured(definition: ActionDefinition) { MVMCoreUIActionHandler.performActionUnstructured(with: definition.model, sourceModel: definition.sourceModel, additionalData: additionalData, delegateObject: delegateObject) } } // MARK: - MVMCoreUIViewConstrainingProtocol extension TestToggle { public func needsToBeConstrained() -> Bool { true } public func horizontalAlignment() -> UIStackView.Alignment { .trailing } } public class TestToggleModel: MoleculeModelProtocol, FormFieldProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- public static var identifier: String = "testToggle" public var backgroundColor: Color? //not used public var selected: Bool = false public var enabled: Bool = true public var readOnly: Bool = false public var action: ActionModelProtocol? public var alternateAction: ActionModelProtocol? public var accessibilityText: String? public var fieldKey: String? public var groupName: String = FormValidator.defaultGroupName public var baseValue: AnyHashable? //-------------------------------------------------- // MARK: - Keys //-------------------------------------------------- private enum CodingKeys: String, CodingKey { case moleculeName case state case enabled case readOnly case action case accessibilityIdentifier case alternateAction case accessibilityText case fieldKey case groupName } //-------------------------------------------------- // MARK: - Form Valdiation //-------------------------------------------------- public func formFieldValue() -> AnyHashable? { guard enabled else { return nil } return selected } //-------------------------------------------------- // MARK: - Server Value //-------------------------------------------------- open func formFieldServerValue() -> AnyHashable? { return formFieldValue() } //-------------------------------------------------- // MARK: - Initializer //-------------------------------------------------- public init(_ state: Bool) { selected = state baseValue = state } //-------------------------------------------------- // MARK: - Codec //-------------------------------------------------- required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) if let state = try typeContainer.decodeIfPresent(Bool.self, forKey: .state) { selected = state } action = try typeContainer.decodeModelIfPresent(codingKey: .action) alternateAction = try typeContainer.decodeModelIfPresent(codingKey: .alternateAction) accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText) baseValue = selected fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey) if let gName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) { groupName = gName } enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier) try container.encodeModelIfPresent(action, forKey: .action) try container.encodeModelIfPresent(alternateAction, forKey: .alternateAction) try container.encode(moleculeName, forKey: .moleculeName) try container.encode(selected, forKey: .state) try container.encode(enabled, forKey: .enabled) try container.encodeIfPresent(fieldKey, forKey: .fieldKey) try container.encodeIfPresent(groupName, forKey: .groupName) try container.encode(readOnly, forKey: .readOnly) } }