Digital PCT265 story PCT-135: More isEquals. Fix replaceChildMolecule signature for TabsListItemModel.

This commit is contained in:
Hedden, Kyle Matthew 2024-05-15 22:24:03 -04:00
parent cd5d9b0c4a
commit ffc36c309f
9 changed files with 129 additions and 15 deletions

View File

@ -162,7 +162,7 @@ import VDS
&& fontName == model.fontName
&& fontSize == model.fontSize
&& textAlignment == model.textAlignment
&& attributes.isEqual(to: model.attributes)
&& attributes.isVisuallyEquivalent(to: model.attributes)
&& html == model.html
&& hero == model.hero
&& makeWholeViewClickable == model.makeWholeViewClickable

View File

@ -106,9 +106,28 @@ open class TabBarModel: MoleculeModelProtocol {
try container.encode(selectedTab, forKey: .selectedTab)
try container.encodeIfPresent(style, forKey: .style)
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor
&& selectedColor == model.selectedColor
&& selectedTab == model.selectedTab
&& style == model.style
&& tabs == model.tabs
}
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor
&& selectedColor == model.selectedColor
&& selectedTab == model.selectedTab
&& style == model.style
&& tabs.isVisuallyEquivalent(to: model.tabs)
}
}
open class TabBarItemModel: Codable {
open class TabBarItemModel: Codable, Equatable, MoleculeModelComparisonProtocol {
open var title: String?
open var image: String
open var action: ActionModelProtocol
@ -142,4 +161,18 @@ open class TabBarItemModel: Codable {
try container.encodeModel(action, forKey: .action)
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
}
public static func == (lhs: TabBarItemModel, rhs: TabBarItemModel) -> Bool {
return lhs.title == rhs.title
&& lhs.image == rhs.image
&& lhs.accessibilityText == rhs.accessibilityText
&& lhs.action.isEqual(to: rhs.action)
}
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return image == model.image
&& accessibilityText == model.accessibilityText
&& title == model.title
}
}

View File

@ -105,11 +105,39 @@ open class TabsModel: MoleculeModelProtocol {
try container.encode(borderLine, forKey: .borderLine)
try container.encodeIfPresent(minWidth, forKey: .minWidth)
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor
&& style == model.style
&& orientation == model.orientation
&& indicatorPosition == model.indicatorPosition
&& overflow == model.overflow
&& fillContainer == model.fillContainer
&& size == model.size
&& borderLine == model.borderLine
&& minWidth == model.minWidth
&& selectedIndex == model.selectedIndex
&& tabs.isEqual(to: model.tabs)
}
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor
&& style == model.style
&& orientation == model.orientation
&& indicatorPosition == model.indicatorPosition
&& overflow == model.overflow
&& fillContainer == model.fillContainer
&& size == model.size
&& borderLine == model.borderLine
&& minWidth == model.minWidth
//&& selectedIndex == model.selectedIndex // Selected index could have been either reset locally or by server. For now ignore.c
&& tabs.isVisuallyEquivalent(to: model.tabs)
}
}
open class TabItemModel: Codable {
open class TabItemModel: Codable, Equatable, MoleculeModelComparisonProtocol {
open var label: LabelModel
open var action: ActionModelProtocol?
@ -146,4 +174,14 @@ open class TabItemModel: Codable {
try container.encodeModel(label, forKey: .label)
try container.encodeModelIfPresent(action, forKey: .action)
}
public static func == (lhs: TabItemModel, rhs: TabItemModel) -> Bool {
return lhs.label.isEqual(to: rhs.label)
&& lhs.action.isEqual(to: rhs.action)
}
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return label.isVisuallyEquivalent(to: model.label)
}
}

View File

@ -23,17 +23,18 @@ public class TabsListItemModel: ListItemModel, ParentMoleculeModelProtocol {
return molecules.flatMap { $0 }
}
public func replaceChildMolecule(with replacementMolecule: MoleculeModelProtocol) throws -> Bool {
guard let replacementMolecule = replacementMolecule as? ListItemModelProtocol & MoleculeModelProtocol else { return false }
public func replaceChildMolecule(with replacementMolecule: MoleculeModelProtocol) throws -> MoleculeModelProtocol? {
guard let replacementMolecule = replacementMolecule as? ListItemModelProtocol & MoleculeModelProtocol else { return nil }
for (tabIndex, _) in molecules.enumerated() {
for (elementIndex, _) in molecules[tabIndex].enumerated() {
if molecules[tabIndex][elementIndex].id == replacementMolecule.id {
let replacedMolecule = molecules[tabIndex][elementIndex]
molecules[tabIndex][elementIndex] = replacementMolecule
return true
return replacedMolecule
}
}
}
return false
return nil
}
//--------------------------------------------------
@ -90,6 +91,20 @@ public class TabsListItemModel: ListItemModel, ParentMoleculeModelProtocol {
try container.encode(tabs, forKey: .tabs)
try container.encodeModels2D(molecules, forKey: .molecules)
}
public override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard super.isEqual(to: model), let model = model as? Self else { return false }
return tabs.isEqual(to: model.tabs)
&& molecules.count == model.molecules.count
&& zip(molecules, model.molecules).allSatisfy({ $0.0.isEqual(to: $0.1) })
}
public override func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
guard super.isVisuallyEquivalent(to: model), let model = model as? Self else { return false }
return tabs.isVisuallyEquivalent(to: model.tabs)
&& molecules.count == model.molecules.count
&& zip(molecules, model.molecules).allSatisfy({ $0.0.isVisuallyEquivalent(to: $0.1) })
}
}
extension TabsListItemModel: PageBehaviorProtocolRequirer {

View File

@ -141,6 +141,17 @@ open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtoc
try container.encodeIfPresent(style, forKey: .style)
try container.encodeIfPresent(titleOffset, forKey: .titleOffset)
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor
&& title == model.title
&& hidden == model.hidden
&& tintColor == model.tintColor
&& line.isEqual(to: model.line)
&& hidesSystemBackButton == model.hidesSystemBackButton
&& style == model.style
}
}
extension NavigationItemModel: ParentMoleculeModelProtocol {

View File

@ -101,6 +101,14 @@ open class HeadlineBodyModel: ParentMoleculeModelProtocol {
&& style == style
&& backgroundColor == backgroundColor
}
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return headline.isVisuallyEquivalent(to: model.headline)
&& body.isVisuallyEquivalent(to: model.body)
&& style == style
&& backgroundColor == backgroundColor
}
}
public extension HeadlineBodyModel {

View File

@ -86,4 +86,12 @@
&& axis == model.axis
&& spacing == model.spacing
}
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor
&& molecules.isVisuallyEquivalent(to: model.molecules)
&& axis == model.axis
&& spacing == model.spacing
}
}

View File

@ -38,7 +38,7 @@ public extension MoleculeTreeTraversalProtocol {
func printMolecules(options: TreeTraversalOptions = .parentFirst) {
depthFirstTraverse(options: options, depth: 1) { depth, molecule, stop in
print("\(String(repeating: ">>", count: depth)) \"\(molecule.moleculeName)\" [\(molecule): \(molecule.id)]")
print("\(String(repeating: ">>", count: depth)) \"\(molecule.moleculeName)\" [\(molecule)]")
}
}

View File

@ -65,17 +65,17 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior, Co
}
fileprivate func findAndReplace(_ moleculeModels: [any MoleculeModelProtocol], in rootMolecules: [any MoleculeModelProtocol]) -> [any MoleculeModelProtocol]? {
debugLog("onPageNew replacing \(moleculeModels.map { $0.id })")
debugLog("attempting to replace \(moleculeModels.map { $0.id }) in \(rootMolecules)")
var hasReplacement = false
let updatedRootMolecules = rootMolecules.map { rootMolecule in
// Top level check to return a new root molecule.
if let updatedMolecule = moleculeModels.first(where: { rootMolecule.id == $0.id }) {
guard !updatedMolecule.isEqual(to: rootMolecule) else {
debugLog("onPageNew molecule \(updatedMolecule) is the same as \(rootMolecule). skipping...")
debugLog("molecule \(updatedMolecule) is the same as \(rootMolecule). skipping...")
return rootMolecule
}
debugLog("onPageNew replacing \(rootMolecule) with \(updatedMolecule)")
debugLog("replacing \(rootMolecule) with \(updatedMolecule)")
logUpdated(molecule: updatedMolecule)
hasReplacement = true
return updatedMolecule
@ -89,10 +89,10 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior, Co
if let replacedMolecule = try parentMolecule.replaceChildMolecule(with: newMolecule) {
guard !replacedMolecule.isEqual(to: newMolecule) else {
// Note: Slight risk here of replacing the something in the original tree and misreporting that is it not replaced based on equality.
debugLog("onPageNew molecule \(newMolecule) is the same as \(replacedMolecule). skipping...")
debugLog("molecule \(newMolecule) is the same as \(replacedMolecule). skipping...")
return
}
debugLog("onPageNew replacing \(replacedMolecule) with \(newMolecule)")
debugLog("replacing \(replacedMolecule) with \(newMolecule)")
logUpdated(molecule: newMolecule)
hasReplacement = true
}
@ -106,6 +106,7 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior, Co
}
return parentMolecule
}
debugLog("replacing \(hasReplacement ? updatedRootMolecules.count : 0) molecules")
return hasReplacement ? updatedRootMolecules : nil
}