diff --git a/MVMCoreUI/Atomic/Extensions/ReadableDecodingErrors.swift b/MVMCoreUI/Atomic/Extensions/ReadableDecodingErrors.swift deleted file mode 100644 index 4b48b0a4..00000000 --- a/MVMCoreUI/Atomic/Extensions/ReadableDecodingErrors.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// ReadableDecodingErrors.swift -// MVMCore -// -// Created by Kyle Hedden on 10/5/23. -// Copyright © 2023 myverizon. All rights reserved. -// - -import Foundation - -protocol HumanReadableDecodingErrorProtocol { - var readableDescription: String { get } -} - -extension JSONError: HumanReadableDecodingErrorProtocol { - var readableDescription: String { - switch (self) { - case .other(let other): - if let other = other as? HumanReadableDecodingErrorProtocol { - return other.readableDescription - } - return description - default: - return description - } - } -} - -extension ModelRegistry.Error: HumanReadableDecodingErrorProtocol { - var readableDescription: String { - switch (self) { - case .decoderErrorModelNotMapped(let identifier, let codingKey, let codingPath) where identifier != nil && codingKey != nil && codingPath != nil: - return "Model identifier \"\(identifier!)\" is not mapped for \"\(codingKey!.stringValue)\" @ \(codingPath!.map { return $0.stringValue })" - - case .decoderErrorObjectNotPresent(let codingKey, let codingPath): - return "Required model \"\(codingKey.stringValue)\" was not found @ \(codingPath.map { return $0.stringValue })" - - default: - return "Registry error: \((self as NSError).localizedFailureReason ?? self.localizedDescription)" - } - } -} - -extension DecodingError: HumanReadableDecodingErrorProtocol { - var readableDescription: String { - switch (self) { - case .keyNotFound(let codingKey, let context): - return "Required key \(codingKey.stringValue) was not found @ \(context.codingPath.map { return $0.stringValue })" - - case .valueNotFound(_, let context): - return "Value not found @ \(context.codingPath.map { return $0.stringValue })" - - case .typeMismatch(_, let context): - return "Value type mismatch @ \(context.codingPath.map { return $0.stringValue })" - - case .dataCorrupted(let context): - return "Data corrupted @ \(context.codingPath.map { return $0.stringValue })" - - @unknown default: - return (self as NSError).localizedFailureReason ?? self.localizedDescription - } - } -} diff --git a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift index 0c65d403..d62fd149 100644 --- a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift @@ -97,12 +97,16 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol bottomViewOutsideOfScrollArea = templateModel?.anchorFooter ?? false super.updateUI(for: molecules) - molecules?.forEach({ molecule in + guard let molecules else { return } + + // For updating individual specfied molecules. (Not a full table reload done in the base class.) These molecule types should remain the same type by replacement standards. + molecules.forEach({ molecule in + // Replace any top level cell data if required. if let index = moleculesInfo?.firstIndex(where: { $0.molecule.id == molecule.id }) { moleculesInfo?[index].molecule = molecule } - newData(for: molecule) }) + newData(for: molecules) } open override func viewDidAppear(_ animated: Bool) { @@ -233,18 +237,27 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol } open func newData(for molecule: MoleculeModelProtocol) { + newData(for: [molecule]) + } + + /// Refreshes all relevant cells for a given set of molecule models. + open func newData(for molecules: [MoleculeModelProtocol]) { //Check header and footer if replace happens then return. - if updateHeaderFooterView(topView, with: molecule) || - updateHeaderFooterView(bottomView, with: molecule, isHeader: false) { - return + molecules.forEach { + if updateHeaderFooterView(topView, with: $0) || + updateHeaderFooterView(bottomView, with: $0, isHeader: false) { + return + } } guard let moleculesInfo = moleculesInfo else { return } let indicies = moleculesInfo.indices.filter({ index -> Bool in - return moleculesInfo[index].molecule.findFirstMolecule(by: { - $0.moleculeName == molecule.moleculeName && equal(moleculeA: molecule, moleculeB: $0) + return moleculesInfo[index].molecule.findFirstMolecule(by: { existingMolecule in + molecules.contains { newMolecule in + existingMolecule.moleculeName == newMolecule.moleculeName && equal(moleculeA: existingMolecule, moleculeB: newMolecule) + } }) != nil }) @@ -253,7 +266,14 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol let indexPaths = indicies.map { return IndexPath(row: $0, section: 0) } - tableView.reloadRows(at: indexPaths, with: .automatic) + + if #available(iOS 15.0, *) { + // All rows should have been layed out already on the first newDataBuildScreen reload with the getMoleculeInfoList call. Therefore, we can be safe to assume the top level cell configuration will not be modified and only the child content will be updated allowing us to levearage this more efficient method. + tableView.reconfigureRows(at: indexPaths) + } else { + // A full reload can cause a flicker / animation. Better to avoid with above reconfigure method. + tableView.reloadRows(at: indexPaths, with: .automatic) + } if let selectedIndex = selectedIndex { tableView.selectRow(at: selectedIndex, animated: false, scrollPosition: .none) } diff --git a/MVMCoreUI/Behaviors/ReplaceableMoleculeBehaviorModel.swift b/MVMCoreUI/Behaviors/ReplaceableMoleculeBehaviorModel.swift index 51428234..233efdcc 100644 --- a/MVMCoreUI/Behaviors/ReplaceableMoleculeBehaviorModel.swift +++ b/MVMCoreUI/Behaviors/ReplaceableMoleculeBehaviorModel.swift @@ -60,6 +60,7 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior { } } if moleculeModels.count > 0 { + // TODO: Getting dropped into the page update queue. Can we get this replaced without an async dispatch to avoid an animation? delegateObject?.moleculeDelegate?.replaceMoleculeData(moleculeModels, completionHandler: nil) } }