generalizing the observing behavior

This commit is contained in:
Kevin G Christiano 2021-06-22 15:05:04 -04:00
parent be196a289e
commit 2b378f5597
5 changed files with 48 additions and 54 deletions

View File

@ -124,7 +124,7 @@ import MVMCore
didSet {
if !updateSelectionOnly {
layoutIfNeeded()
(model as? CheckboxModel)?.checked = isSelected
(model as? CheckboxModel)?.selected = isSelected
shapeLayer?.removeAllAnimations()
updateCheckboxUI(isSelected: isSelected, isAnimated: isAnimated)
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
@ -419,8 +419,8 @@ import MVMCore
isAnimated = model.animated
isRound = model.round
if model.checked {
checkAndBypassAnimations(selected: model.checked)
if model.selected {
checkAndBypassAnimations(selected: model.selected)
}
isEnabled = model.enabled

View File

@ -15,7 +15,7 @@
public static var identifier: String = "checkbox"
public var backgroundColor: Color?
public var accessibilityIdentifier: String?
public dynamic var checked: Bool = false
public dynamic var selected: Bool = false
public var enabled: Bool = true
public var animated: Bool = true
public var inverted: Bool = false
@ -69,26 +69,22 @@
// MARK: - Form Validation
//--------------------------------------------------
public func formFieldValue() -> AnyHashable? { checked }
public func formFieldValue() -> AnyHashable? { selected }
//--------------------------------------------------
// MARK: - Selectable Protocol
//--------------------------------------------------
public func select(as isSelected: Bool) {
checked = isSelected
selected = isSelected
}
public var selectedValue: Bool {
checked
}
//--------------------------------------------------
// MARK: - Initializer
//--------------------------------------------------
public init(isChecked: Bool = false) {
self.checked = isChecked
self.selected = isChecked
baseValue = isChecked
}
@ -142,10 +138,10 @@
}
if let checked = try typeContainer.decodeIfPresent(Bool.self, forKey: .checked) {
self.checked = checked
self.selected = checked
}
baseValue = checked
baseValue = selected
if let animated = try typeContainer.decodeIfPresent(Bool.self, forKey: .animated) {
self.animated = animated
@ -179,7 +175,7 @@
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
try container.encodeIfPresent(borderColor, forKey: .borderColor)
try container.encode(borderWidth, forKey: .borderWidth)
try container.encode(checked, forKey: .checked)
try container.encode(selected, forKey: .checked)
try container.encode(inverted, forKey: .inverted)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encodeIfPresent(checkColor, forKey: .checkColor)

View File

@ -98,7 +98,7 @@ public typealias ActionBlockConfirmation = () -> (Bool)
self.constrainKnob()
}
toggleModel?.state = isOn
toggleModel?.selected = isOn
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
accessibilityValue = isOn ? MVMCoreUIUtility.hardcodedString(withKey: "AccOn") : MVMCoreUIUtility.hardcodedString(withKey: "AccOff")
setNeedsLayout()
@ -381,7 +381,7 @@ public typealias ActionBlockConfirmation = () -> (Bool)
containerTintColor.off = model.offTintColor.uiColor
knobTintColor.on = model.onKnobTintColor.uiColor
knobTintColor.off = model.offKnobTintColor.uiColor
isOn = model.state
isOn = model.selected
changeStateNoAnimation(isOn)
isAnimated = model.animated
isEnabled = model.enabled

View File

@ -7,7 +7,7 @@
//
public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableModelProtocol, SelectableMoleculeModel {
public class ToggleModel: NSObject, MoleculeModelProtocol, FormFieldProtocol, EnableableModelProtocol, SelectableMoleculeModel {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
@ -15,7 +15,7 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo
public static var identifier: String = "toggle"
public var accessibilityIdentifier: String?
public var backgroundColor: Color?
public var state: Bool = false
public dynamic var selected: Bool = false
public var animated: Bool = true
public var enabled: Bool = true
public var action: ActionModelProtocol?
@ -56,18 +56,14 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo
// MARK: - Form Valdiation
//--------------------------------------------------
public func formFieldValue() -> AnyHashable? { state }
public func formFieldValue() -> AnyHashable? { selected }
//--------------------------------------------------
// MARK: - Selectable Protocol
//--------------------------------------------------
public func select(as isSelected: Bool) {
state = isSelected
}
public var selectedValue: Bool {
state
selected = isSelected
}
//--------------------------------------------------
@ -75,7 +71,7 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo
//--------------------------------------------------
public init(_ state: Bool) {
self.state = state
self.selected = state
baseValue = state
}
@ -87,7 +83,7 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
if let state = try typeContainer.decodeIfPresent(Bool.self, forKey: .state) {
self.state = state
self.selected = state
}
if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) {
@ -121,7 +117,7 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo
accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText)
baseValue = state
baseValue = selected
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
self.groupName = groupName
@ -135,7 +131,7 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo
try container.encodeModelIfPresent(action, forKey: .action)
try container.encodeModelIfPresent(alternateAction, forKey: .alternateAction)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(state, forKey: .state)
try container.encode(selected, forKey: .state)
try container.encode(animated, forKey: .animated)
try container.encode(enabled, forKey: .enabled)
try container.encode(onTintColor, forKey: .onTintColor)

View File

@ -9,8 +9,8 @@
/// Protocol to apply to any model of a UI Control with a binary on/off nature.
///
/// Example classes: Checkbox or Switch.
public protocol SelectableMoleculeModel {
var selectedValue: Bool { get }
@objc public protocol SelectableMoleculeModel: AnyObject {
@objc dynamic var selected: Bool { get set }
func select(as isSelected: Bool)
}
@ -84,31 +84,33 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior, PageMolecu
public func onPageNew(rootMolecules: [MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject) {
let selectableModels: [SelectableMoleculeModel] = rootMolecules.allMoleculesOfType()
let selectableModels: [(NSObject & SelectableMoleculeModel)] = rootMolecules.allMoleculesOfType()
guard !selectableModels.isEmpty else { return }
for model in selectableModels {
if let checkboxModel = model as? CheckboxModel, let key = checkboxModel.fieldKey {
if let key = (model as? FormFieldProtocol)?.fieldKey {
valuesMirror[key] = model.selected
setObserver(model, fieldKey: key)
}
}
}
func setObserver<T>(_ model: T, fieldKey: String) where T: (NSObject & SelectableMoleculeModel) {
observers[fieldKey] = model.observe(\.selected, options: [.new]) { [weak self] model, change in
guard let self = self,
let isChecked = change.newValue
else { return }
self.valuesMirror[fieldKey] = isChecked
// If all are models are in the opposite state of the behavior, then realign.
if self.selectAllIsMisaligned() {
self.realignPageBehavior(asSelectAll: true)
valuesMirror[key] = checkboxModel.checked
observers[key] = checkboxModel.observe(\.checked, options: [.new]) { [weak self] model, change in
guard let self = self,
let isChecked = change.newValue,
let key = model.fieldKey
else { return }
self.valuesMirror[key] = isChecked
// If all are models are in the opposite state of the behavior, then realign.
if self.selectAllIsMisaligned() {
self.realignPageBehavior(asSelectAll: true)
} else if self.deselectAllIsMisaligned() {
self.realignPageBehavior(asSelectAll: false)
}
}
} else if self.deselectAllIsMisaligned() {
self.realignPageBehavior(asSelectAll: false)
}
}
}
@ -201,13 +203,13 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior, PageMolecu
/// - Parameter model: A model object assined to the SelectableModel protocol
/// - Returns: Boolean determining if the passed model should be selected.
func toSelect(model: SelectableMoleculeModel) -> Bool {
didSelectAllState && !model.selectedValue
didSelectAllState && !model.selected
}
/// Convenience function making it easier to read if a current selectable model should be acted on.
/// - Parameter model: A model object assined to the SelectableModel protocol
/// - Returns: Boolean determining if the passed model should be deselected.
func toDeselect(model: SelectableMoleculeModel) -> Bool {
!didSelectAllState && model.selectedValue
!didSelectAllState && model.selected
}
}