Digital PCT265 story ONEAPP-7249 - isVisuallyEquivalent build out to work with stabilizing carousel refreshes.

This commit is contained in:
Hedden, Kyle Matthew 2024-05-08 20:34:08 -04:00
parent 067f63e6de
commit 04581558e3
31 changed files with 248 additions and 62 deletions

View File

@ -187,7 +187,7 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
try container.encodeIfPresent(disabledAccessibilityTraits, forKey: .disabledAccessibilityTraits) try container.encodeIfPresent(disabledAccessibilityTraits, forKey: .disabledAccessibilityTraits)
} }
public func isEqual(to model: any ModelProtocol) -> Bool { public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false } guard let model = model as? Self else { return false }
return title == model.title return title == model.title
&& enabled == model.enabled && enabled == model.enabled
@ -195,11 +195,25 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
&& action.isEqual(to: model.action) && action.isEqual(to: model.action)
&& accessibilityText == model.accessibilityText && accessibilityText == model.accessibilityText
&& accessibilityIdentifier == model.accessibilityIdentifier && accessibilityIdentifier == model.accessibilityIdentifier
&& accessibilityTraits == model.accessibilityTraits
&& disabledAccessibilityTraits == model.disabledAccessibilityTraits
&& style == model.style && style == model.style
&& size == model.size && size == model.size
&& groupName == model.groupName && groupName == model.groupName
&& width == model.width && width == model.width
}
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return title == model.title
&& enabled == model.enabled
&& inverted == model.inverted
&& accessibilityText == model.accessibilityText
&& accessibilityIdentifier == model.accessibilityIdentifier
&& accessibilityTraits == model.accessibilityTraits && accessibilityTraits == model.accessibilityTraits
&& disabledAccessibilityTraits == model.disabledAccessibilityTraits && disabledAccessibilityTraits == model.disabledAccessibilityTraits
&& style == model.style
&& size == model.size
&& width == model.width
} }
} }

View File

@ -100,7 +100,7 @@ open class LinkModel: ButtonModelProtocol, MoleculeModelProtocol, EnableableMode
try container.encode(shouldMaskRecordedView, forKey: .shouldMaskRecordedView) try container.encode(shouldMaskRecordedView, forKey: .shouldMaskRecordedView)
} }
public func isEqual(to model: any ModelProtocol) -> Bool { public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false } guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor return backgroundColor == model.backgroundColor
&& title == model.title && title == model.title
@ -110,7 +110,18 @@ open class LinkModel: ButtonModelProtocol, MoleculeModelProtocol, EnableableMode
&& enabled == model.enabled && enabled == model.enabled
&& size == model.size && size == model.size
&& shouldMaskRecordedView == model.shouldMaskRecordedView && shouldMaskRecordedView == model.shouldMaskRecordedView
// && action.isEqual(to: model.action) // TODO: Move to isVisiuallyEquivalent. && action.isEqual(to: model.action)
}
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor
&& title == model.title
&& accessibilityText == model.accessibilityText
&& accessibilityIdentifier == model.accessibilityIdentifier
&& inverted == model.inverted
&& enabled == model.enabled
&& size == model.size
} }
} }

View File

@ -21,6 +21,8 @@ open class CarouselIndicatorModel: CarouselPagingModelProtocol, MoleculeModelPro
public var id: String = UUID().uuidString public var id: String = UUID().uuidString
public var backgroundColor: Color? public var backgroundColor: Color?
public var moleculeName: String? public var moleculeName: String?
// Assigned and computed by parent.
public var numberOfPages: Int = 0 public var numberOfPages: Int = 0
/// Sets the current Index to focus on. /// Sets the current Index to focus on.
@ -49,7 +51,6 @@ open class CarouselIndicatorModel: CarouselPagingModelProtocol, MoleculeModelPro
case moleculeName case moleculeName
case backgroundColor case backgroundColor
case currentIndex case currentIndex
case numberOfPages
case alwaysSendAction case alwaysSendAction
case animated case animated
case hidesForSinglePage case hidesForSinglePage
@ -118,7 +119,6 @@ open class CarouselIndicatorModel: CarouselPagingModelProtocol, MoleculeModelPro
try container.encode(id, forKey: .id) try container.encode(id, forKey: .id)
try container.encodeIfPresent(moleculeName, forKey: .moleculeName) try container.encodeIfPresent(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
try container.encode(numberOfPages, forKey: .numberOfPages)
try container.encode(currentIndex, forKey: .currentIndex) try container.encode(currentIndex, forKey: .currentIndex)
try container.encode(alwaysSendAction, forKey: .alwaysSendAction) try container.encode(alwaysSendAction, forKey: .alwaysSendAction)
try container.encode(animated, forKey: .animated) try container.encode(animated, forKey: .animated)
@ -131,10 +131,9 @@ open class CarouselIndicatorModel: CarouselPagingModelProtocol, MoleculeModelPro
try container.encodeIfPresent(position, forKey: .position) try container.encodeIfPresent(position, forKey: .position)
} }
public func isEqual(to model: any ModelProtocol) -> Bool { public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false } guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor return backgroundColor == model.backgroundColor
&& numberOfPages == model.numberOfPages
&& currentIndex == model.currentIndex && currentIndex == model.currentIndex
&& alwaysSendAction == model.alwaysSendAction && alwaysSendAction == model.alwaysSendAction
&& animated == model.animated && animated == model.animated

View File

@ -49,8 +49,12 @@ open class LabelAttributeActionModel: LabelAttributeModel {
try container.encodeModel(action, forKey: .action) try container.encodeModel(action, forKey: .action)
} }
public override func isEqual(to model: any ModelProtocol) -> Bool { public override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard super.isEqual(to: model), let model = model as? Self else { return false } guard super.isEqual(to: model), let model = model as? Self else { return false }
return action.isEqual(to: model.action) return action.isEqual(to: model.action)
} }
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
return super.isEqual(to: model)
}
} }

View File

@ -44,7 +44,7 @@
try container.encodeIfPresent(textColor, forKey: .textColor) try container.encodeIfPresent(textColor, forKey: .textColor)
} }
public override func isEqual(to model: any ModelProtocol) -> Bool { public override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard super.isEqual(to: model), let model = model as? Self else { return false } guard super.isEqual(to: model), let model = model as? Self else { return false }
return textColor == model.textColor return textColor == model.textColor
} }

View File

@ -56,7 +56,7 @@
try container.encodeIfPresent(size, forKey: .size) try container.encodeIfPresent(size, forKey: .size)
} }
public override func isEqual(to model: any ModelProtocol) -> Bool { public override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard super.isEqual(to: model), let model = model as? Self else { return false } guard super.isEqual(to: model), let model = model as? Self else { return false }
return style == model.style return style == model.style
&& name == model.name && name == model.name

View File

@ -70,7 +70,7 @@ class LabelAttributeImageModel: LabelAttributeModel {
try container.encodeIfPresent(tintColor, forKey: .tintColor) try container.encodeIfPresent(tintColor, forKey: .tintColor)
} }
public override func isEqual(to model: any ModelProtocol) -> Bool { public override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard super.isEqual(to: model), let model = model as? Self else { return false } guard super.isEqual(to: model), let model = model as? Self else { return false }
return URL == model.URL return URL == model.URL
&& name == model.name && name == model.name

View File

@ -7,7 +7,7 @@
// //
@objcMembers open class LabelAttributeModel: ModelProtocol { @objcMembers open class LabelAttributeModel: ModelProtocol, ModelComparisonProtocol, MoleculeModelComparisonProtocol {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Properties // MARK: - Properties
//-------------------------------------------------- //--------------------------------------------------
@ -76,7 +76,7 @@
try container.encode(length, forKey: .length) try container.encode(length, forKey: .length)
} }
public func isEqual(to model: any ModelProtocol) -> Bool { public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false } guard let model = model as? Self else { return false }
return location == model.location return location == model.location
&& length == model.length && length == model.length

View File

@ -67,7 +67,7 @@ import UIKit
try container.encodeIfPresent(pattern, forKey: .pattern) try container.encodeIfPresent(pattern, forKey: .pattern)
} }
public override func isEqual(to model: any ModelProtocol) -> Bool { public override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard super.isEqual(to: model), let model = model as? Self else { return false } guard super.isEqual(to: model), let model = model as? Self else { return false }
return style == model.style return style == model.style
&& color == model.color && color == model.color

View File

@ -133,7 +133,7 @@ import VDS
try container.encodeIfPresent(accessibilityTraits, forKey: .accessibilityTraits) try container.encodeIfPresent(accessibilityTraits, forKey: .accessibilityTraits)
} }
public func isEqual(to model: any ModelProtocol) -> Bool { public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false } guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor return backgroundColor == model.backgroundColor
&& text == model.text && text == model.text
@ -143,12 +143,31 @@ import VDS
&& fontName == model.fontName && fontName == model.fontName
&& fontSize == model.fontSize && fontSize == model.fontSize
&& textAlignment == model.textAlignment && textAlignment == model.textAlignment
&& attributes.areEqual(to: model.attributes) && attributes.isEqual(to: model.attributes)
&& html == model.html && html == model.html
&& hero == model.hero && hero == model.hero
&& makeWholeViewClickable == model.makeWholeViewClickable && makeWholeViewClickable == model.makeWholeViewClickable
&& numberOfLines == model.numberOfLines && numberOfLines == model.numberOfLines
&& accessibilityTraits == model.accessibilityTraits
&& inverted == inverted
&& shouldMaskRecordedView == model.shouldMaskRecordedView && shouldMaskRecordedView == model.shouldMaskRecordedView
}
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor
&& text == model.text
&& textColor == model.textColor
&& fontStyle == model.fontStyle
&& fontName == model.fontName
&& fontSize == model.fontSize
&& textAlignment == model.textAlignment
&& attributes.isEqual(to: model.attributes)
&& html == model.html
&& hero == model.hero
&& makeWholeViewClickable == model.makeWholeViewClickable
&& numberOfLines == model.numberOfLines
&& accessibilityText == model.accessibilityText
&& accessibilityTraits == model.accessibilityTraits && accessibilityTraits == model.accessibilityTraits
&& inverted == inverted && inverted == inverted
} }

View File

@ -130,7 +130,7 @@ public class LineModel: MoleculeModelProtocol, Invertable {
try container.encode(orientation == .vertical, forKey: .useVerticalLine) try container.encode(orientation == .vertical, forKey: .useVerticalLine)
} }
public func isEqual(to model: any ModelProtocol) -> Bool { public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false } guard let model = model as? Self else { return false }
return type == model.type return type == model.type
&& inverted == model.inverted && inverted == model.inverted

View File

@ -68,9 +68,4 @@ public class ListOneColumnFullWidthTextBodyTextModel: ListItemModel, MoleculeMod
try container.encode(moleculeName, forKey: .moleculeName) try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(headlineBody, forKey: .headlineBody) try container.encode(headlineBody, forKey: .headlineBody)
} }
public func isEqual(to model: any ModelProtocol) -> Bool {
guard let model = model as? Self else { return false }
return headlineBody.isEqual(to: headlineBody)
}
} }

View File

@ -46,14 +46,24 @@ public class TitleLockupModel: ParentMoleculeModelProtocol {
return nil return nil
} }
public func isEqual(to model: any ModelProtocol) -> Bool { public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false } guard let model = model as? Self else { return false }
return textAlignment == model.textAlignment return textAlignment == model.textAlignment
&& subTitleColor == model.subTitleColor && subTitleColor == model.subTitleColor
&& alignment == model.alignment && alignment == model.alignment
&& inverted == model.inverted && inverted == model.inverted
&& backgroundColor == model.backgroundColor && backgroundColor == model.backgroundColor
&& children.areEqual(to: model.children) && children.isEqual(to: model.children)
}
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return textAlignment == model.textAlignment
&& subTitleColor == model.subTitleColor
&& alignment == model.alignment
&& inverted == model.inverted
&& backgroundColor == model.backgroundColor
&& children.isVisuallyEquivalent(to: model.children)
} }
//-------------------------------------------------- //--------------------------------------------------

View File

@ -91,7 +91,7 @@
try container.encode(readOnly, forKey: .readOnly) try container.encode(readOnly, forKey: .readOnly)
} }
public override func isEqual(to model: any ModelProtocol) -> Bool { public override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard super.isEqual(to: model), let model = model as? Self else { return false } guard super.isEqual(to: model), let model = model as? Self else { return false }
return peakingUI == model.peakingUI return peakingUI == model.peakingUI
&& peakingArrowColor == model.peakingArrowColor && peakingArrowColor == model.peakingArrowColor
@ -100,4 +100,12 @@
&& enabled == model.enabled && enabled == model.enabled
&& readOnly == model.readOnly && readOnly == model.readOnly
} }
public override func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
guard super.isVisuallyEquivalent(to: model), let model = model as? Self else { return false }
return peakingUI == model.peakingUI
&& peakingArrowColor == model.peakingArrowColor
&& enabled == model.enabled
&& readOnly == model.readOnly
}
} }

View File

@ -8,7 +8,7 @@
// A base class that has common list item boilerplate model stuffs. // A base class that has common list item boilerplate model stuffs.
import MVMCore import MVMCore
@objcMembers open class ListItemModel: ContainerModel, ListItemModelProtocol { @objcMembers open class ListItemModel: ContainerModel, ListItemModelProtocol, ModelComparisonProtocol, MoleculeModelComparisonProtocol {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Properties // MARK: - Properties
@ -23,6 +23,7 @@ import MVMCore
public var accessibilityTraits: UIAccessibilityTraits? public var accessibilityTraits: UIAccessibilityTraits?
public var accessibilityValue: String? public var accessibilityValue: String?
public var accessibilityText: String? public var accessibilityText: String?
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Keys // MARK: - Keys
//-------------------------------------------------- //--------------------------------------------------
@ -129,4 +130,29 @@ import MVMCore
try container.encodeIfPresent(accessibilityValue, forKey: .accessibilityValue) try container.encodeIfPresent(accessibilityValue, forKey: .accessibilityValue)
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText) try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
} }
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor
&& hideArrow == model.hideArrow
&& style == model.style
&& gone == model.gone
&& accessibilityText == model.accessibilityText
&& accessibilityValue == model.accessibilityValue
&& accessibilityTraits == model.accessibilityTraits
&& line.isEqual(to: model.line)
&& action.isEqual(to: model.action)
}
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor
&& hideArrow == model.hideArrow
&& style == model.style
&& gone == model.gone
&& accessibilityText == model.accessibilityText
&& accessibilityValue == model.accessibilityValue
&& accessibilityTraits == model.accessibilityTraits
&& line.isVisuallyEquivalent(to: model.line)
}
} }

View File

@ -74,9 +74,14 @@
try super.encode(to: encoder) try super.encode(to: encoder)
} }
public override func isEqual(to model: any ModelProtocol) -> Bool { public override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard super.isEqual(to: model), let model = model as? Self else { return false } guard super.isEqual(to: model), let model = model as? Self else { return false }
return action.isEqual(to: model.action) return border == border
&& border == border && action.isEqual(to: model.action)
}
public override func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
guard super.isVisuallyEquivalent(to: model), let model = model as? Self else { return false }
return border == border
} }
} }

View File

@ -53,17 +53,13 @@ import MVMCore
try container.encodeModel(molecule, forKey: .molecule) try container.encodeModel(molecule, forKey: .molecule)
} }
public func isEqual(to model: any ModelProtocol) -> Bool { public override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false } guard super.isEqual(to: model), let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor return molecule.isEqual(to: model)
&& action.isEqual(to: model.action) }
&& hideArrow == model.hideArrow
&& line.isEqual(to: model.line) public override func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
&& style == model.style guard super.isVisuallyEquivalent(to: model), let model = model as? Self else { return false }
&& gone == model.gone return molecule.isVisuallyEquivalent(to: model.molecule)
&& molecule.isEqual(to: model.molecule)
&& accessibilityTraits == model.accessibilityTraits
&& accessibilityValue == model.accessibilityValue
&& accessibilityText == model.accessibilityText
} }
} }

View File

@ -59,10 +59,16 @@
try container.encode(gone, forKey: .gone) try container.encode(gone, forKey: .gone)
} }
public override func isEqual(to model: any ModelProtocol) -> Bool { public override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard super.isEqual(to: model), let model = model as? Self else { return false } guard super.isEqual(to: model), let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor return spacing == model.spacing
&& spacing == model.spacing && percent == model.percent
&& gone == model.gone
}
public override func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
guard super.isVisuallyEquivalent(to: model), let model = model as? Self else { return false }
return spacing == model.spacing
&& percent == model.percent && percent == model.percent
&& gone == model.gone && gone == model.gone
} }

View File

@ -30,7 +30,10 @@ import UIKit
} }
public override class func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? { public override class func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? {
MoleculeContainer.nameForReuse(with: model, delegateObject) if let listModel = model as? ListItemModel, listModel.hasStableId {
return "\(MoleculeContainer.nameForReuse(with: model, delegateObject) ?? "")<\(listModel.id)>"
}
return MoleculeContainer.nameForReuse(with: model, delegateObject)
} }
public override class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? { public override class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {

View File

@ -37,7 +37,7 @@
fatalError("init(from:) has not been implemented") fatalError("init(from:) has not been implemented")
} }
public func isEqual(to model: any ModelProtocol) -> Bool { public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false } guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor return backgroundColor == model.backgroundColor
&& spacing == model.spacing && spacing == model.spacing

View File

@ -62,9 +62,14 @@ open class MoleculeContainerModel: ContainerModel, MoleculeContainerModelProtoco
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
} }
public func isEqual(to model: any ModelProtocol) -> Bool { public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false } guard let model = model as? Self else { return false }
return molecule.isEqual(to: model.molecule) return molecule.isEqual(to: model.molecule)
&& backgroundColor == model.backgroundColor && backgroundColor == model.backgroundColor
} }
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor
}
} }

View File

@ -107,9 +107,9 @@ public class EyebrowHeadlineBodyLinkModel: ParentMoleculeModelProtocol {
try container.encodeIfPresent(link, forKey: .link) try container.encodeIfPresent(link, forKey: .link)
} }
public func isEqual(to model: any ModelProtocol) -> Bool { public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false } guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor return backgroundColor == model.backgroundColor
&& children.areEqual(to: model.children) && children.isEqual(to: model.children)
} }
} }

View File

@ -94,7 +94,7 @@ open class HeadlineBodyModel: ParentMoleculeModelProtocol {
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
} }
public func isEqual(to model: any ModelProtocol) -> Bool { public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false } guard let model = model as? Self else { return false }
return headline.isEqual(to: model.headline) return headline.isEqual(to: model.headline)
&& body.isEqual(to: model.body) && body.isEqual(to: model.body)

View File

@ -166,9 +166,19 @@ open class Carousel: View {
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
self.delegateObject = delegateObject self.delegateObject = delegateObject
let originalModel = self.model as? CarouselModel
super.set(with: model, delegateObject, additionalData) super.set(with: model, delegateObject, additionalData)
guard let carouselModel = model as? CarouselModel else { return } guard let carouselModel = model as? CarouselModel else { return }
if #available(iOS 15.0, *) {
if let originalModel, carouselModel.isVisuallyEquivalent(to: originalModel) {
collectionView.reconfigureItems(at: collectionView.indexPathsForVisibleItems)
FormValidator.setupValidation(for: carouselModel, delegate: delegateObject?.formHolderDelegate)
return
}
}
accessibilityLabel = carouselModel.accessibilityText accessibilityLabel = carouselModel.accessibilityText
collectionView.layer.borderColor = UIColor.mvmCoolGray3.cgColor collectionView.layer.borderColor = UIColor.mvmCoolGray3.cgColor
collectionView.layer.borderWidth = (carouselModel.border ?? false) ? 1 : 0 collectionView.layer.borderWidth = (carouselModel.border ?? false) ? 1 : 0

View File

@ -172,10 +172,10 @@ import UIKit
try container.encode(readOnly, forKey: .readOnly) try container.encode(readOnly, forKey: .readOnly)
} }
public func isEqual(to model: any ModelProtocol) -> Bool { public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false } guard let model = model as? Self else { return false }
return backgroundColor == backgroundColor return backgroundColor == backgroundColor
&& molecules.areEqual(to: model.molecules) && molecules.isEqual(to: model.molecules)
&& spacing == model.spacing && spacing == model.spacing
&& border == model.border && border == model.border
&& loop == model.loop && loop == model.loop
@ -194,6 +194,27 @@ import UIKit
&& enabled == model.enabled && enabled == model.enabled
&& readOnly == model.readOnly && readOnly == model.readOnly
} }
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return backgroundColor == backgroundColor
&& spacing == model.spacing
&& border == model.border
&& loop == model.loop
&& height == model.height
&& itemWidthPercent == model.itemWidthPercent
&& itemAlignment == model.itemAlignment
&& paging == model.paging
&& useHorizontalMargins == model.useHorizontalMargins
&& leftPadding == model.leftPadding
&& rightPadding == model.rightPadding
&& accessibilityText == model.accessibilityText
&& baseValue == model.baseValue
&& enabled == model.enabled
&& readOnly == model.readOnly
&& pagingMolecule.isVisuallyEquivalent(to: model.pagingMolecule)
&& molecules.isVisuallyEquivalent(to: model.molecules)
}
} }
extension CarouselModel { extension CarouselModel {

View File

@ -79,10 +79,10 @@
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
} }
public func isEqual(to model: any ModelProtocol) -> Bool { public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false } guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor return backgroundColor == model.backgroundColor
&& molecules.areEqual(to: model.molecules) && molecules.isEqual(to: model.molecules)
&& axis == model.axis && axis == model.axis
&& spacing == model.spacing && spacing == model.spacing
} }

View File

@ -8,11 +8,12 @@
import Foundation import Foundation
public protocol MoleculeModelComparisonProtocol: ModelProtocol { public protocol MoleculeModelComparisonProtocol: ModelComparisonProtocol {
/** True if there are no visual differences between models. /**
True if there are no visual differences between models.
By default if the models are equal then they are visually equivalent. However, if there are parts of models that can be upddated without a UI update, this could be subset of properties. By default if the models are equal then they are visually equivalent. However, if there are parts of models that can be upddated without a UI update, this could be subset of properties.
**/ **/
func isVisuallyEquivalent(to model: MoleculeModelComparisonProtocol) -> Bool func isVisuallyEquivalent(to model: MoleculeModelComparisonProtocol) -> Bool
} }
@ -23,3 +24,39 @@ extension MoleculeModelComparisonProtocol {
return isEqual(to: model) return isEqual(to: model)
} }
} }
public extension Optional {
/// Checks if the curent model is equal to another model.
func isVisuallyEquivalent(to model: MoleculeModelComparisonProtocol?) -> Bool {
guard let self = self as? MoleculeModelComparisonProtocol else {
return model == nil
}
guard let model = model else {
return false
}
return self.isVisuallyEquivalent(to: model)
}
}
public extension Collection {
/// Checks if all the models in the given collection match another given collection.
func isVisuallyEquivalent(to models: [MoleculeModelComparisonProtocol]) -> Bool {
guard count == models.count, let self = self as? [MoleculeModelComparisonProtocol] else { return false }
return models.indices.allSatisfy { index in
self[index].isVisuallyEquivalent(to: models[index])
}
}
}
public extension Optional where Wrapped: Collection {
func isVisuallyEquivalent(to models: [MoleculeModelComparisonProtocol]?) -> Bool {
guard let self = self as? [MoleculeModelComparisonProtocol] else {
return models == nil
}
guard let models = models else {
return false
}
return self.isVisuallyEquivalent(to: models)
}
}

View File

@ -19,7 +19,7 @@ public extension MoleculeModelProtocol {
static var categoryCodingKey: String { "moleculeName" } static var categoryCodingKey: String { "moleculeName" }
func isEqual(to model: any ModelProtocol) -> Bool { func isEqual(to model: ModelProtocol) -> Bool {
guard let model = model as? Self else { return false } guard let model = model as? Self else { return false }
return id == model.id return id == model.id
} }

View File

@ -69,7 +69,12 @@ public extension ParentMoleculeModelProtocol {
func isEqual(to model: any ModelProtocol) -> Bool { func isEqual(to model: any ModelProtocol) -> Bool {
guard let model = model as? Self else { return false } guard let model = model as? Self else { return false }
return model.children.areEqual(to: model.children) return model.children.isEqual(to: model.children)
}
func areVisuallyEquivalent(to model: any ModelProtocol) -> Bool {
guard let model = model as? Self else { return false }
return model.children.isVisuallyEquivalent(to: model.children)
} }
func reduceDepthFirstTraverse<Result>(options: TreeTraversalOptions, depth: Int, initialResult: Result, nextPartialResult: (Result, MoleculeModelProtocol, Int) -> Result) -> Result { func reduceDepthFirstTraverse<Result>(options: TreeTraversalOptions, depth: Int, initialResult: Result, nextPartialResult: (Result, MoleculeModelProtocol, Int) -> Result) -> Result {
@ -119,7 +124,14 @@ public extension ParentMoleculeModelProtocol {
extension ParentModelProtocol { extension ParentModelProtocol {
func deepCompare(_ anotherParent: ParentModelProtocol, with test: (ModelProtocol, ModelProtocol)->Bool) -> (Bool, myChild: ModelProtocol?, theirChild: ModelProtocol?) { public typealias DeepCompareResult = (matched: Bool, myChild: ModelProtocol?, theirChild: ModelProtocol?)
public func deepEquals(to model: any ModelProtocol) -> DeepCompareResult {
guard let model = model as? ParentModelProtocol else { return (false, self, model) }
return deepCompare(model) { $0.isEqual(to: $1) }
}
func deepCompare(_ anotherParent: ParentModelProtocol, with test: (ModelProtocol, ModelProtocol)->Bool) -> DeepCompareResult {
guard test(self, anotherParent) else { return (false, myChild: self, theirChild: self)} guard test(self, anotherParent) else { return (false, myChild: self, theirChild: self)}

View File

@ -522,7 +522,8 @@ import MVMCore
return (model, replacedMolecule) return (model, replacedMolecule)
} }
let uiUpdatedModels: [MoleculeModelProtocol] = replacedModels.compactMap { new, existing in let uiUpdatedModels: [MoleculeModelProtocol] = replacedModels.compactMap { new, existing in
guard !new.isVisuallyEquivalent(to: existing) else { guard !new.isEqual(to: existing) else {
MVMCoreLoggingHandler.shared()?.handleDebugMessage("UI for molecules: \(new) is the same. Skip UI update.")
return nil return nil
} }
return new return new

View File

@ -14,6 +14,7 @@ open class ContainerModel: ContainerModelProtocol, Codable {
//-------------------------------------------------- //--------------------------------------------------
public var id: String = UUID().uuidString public var id: String = UUID().uuidString
public var hasStableId = false
public var horizontalAlignment: UIStackView.Alignment? public var horizontalAlignment: UIStackView.Alignment?
public var useHorizontalMargins: Bool? public var useHorizontalMargins: Bool?
@ -78,7 +79,10 @@ open class ContainerModel: ContainerModelProtocol, Codable {
required public init(from decoder: Decoder) throws { required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self) let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString if let id = try typeContainer.decodeIfPresent(String.self, forKey: .id) {
self.id = id
hasStableId = true
}
if let verticalAlignmentString = try typeContainer.decodeIfPresent(String.self, forKey: .verticalAlignment) { if let verticalAlignmentString = try typeContainer.decodeIfPresent(String.self, forKey: .verticalAlignment) {
verticalAlignment = ContainerHelper.getAlignment(for: verticalAlignmentString) verticalAlignment = ContainerHelper.getAlignment(for: verticalAlignmentString)