Digital PCT265 story PCT-135: Change filtering fix, disable partial page updates, move manager newDataReceived.

This commit is contained in:
Hedden, Kyle Matthew 2024-05-21 14:00:07 -04:00
parent 8135a126ed
commit f403e34d7d

View File

@ -105,10 +105,6 @@ import MVMCore
hasDataUpdate = true hasDataUpdate = true
loadObject.pageJSON = pagesLoaded.optionalDictionaryForKey(pageType) loadObject.pageJSON = pagesLoaded.optionalDictionaryForKey(pageType)
// TODO: Parse parsePageJSON modifies the page model on a different thread than
// the UI update which could cause discrepancies. Parse should return the resulting
// object and assignment should be synchronized on handleNewData(model: ).
// Separate page updates from the module updates to avoid unecessary resets to behaviors and full re-renders. // Separate page updates from the module updates to avoid unecessary resets to behaviors and full re-renders.
do { do {
pageModel = try parsePageJSON(loadObject: loadObject) pageModel = try parsePageJSON(loadObject: loadObject)
@ -262,11 +258,13 @@ import MVMCore
// Replace again in case there is a template level child. // Replace again in case there is a template level child.
if let replaced = try? newTemplateModel.replaceChildMolecule(with: molecule) { if let replaced = try? newTemplateModel.replaceChildMolecule(with: molecule) {
// Only recognize the molecules that actually changed. // Only recognize the molecules that actually changed.
debugLog("Behavior updated \(changes) in template model.") if changes.count > 0 {
changes = changes.filter({ model in debugLog("\(behavior) updated \(changes) in template model.")
behaviorUpdatedModels.contains { $0.id == model.id } changes = changes.filter({ model in
}) !behaviorUpdatedModels.contains { $0.id == model.id }
behaviorUpdatedModels.append(contentsOf: changes) })
behaviorUpdatedModels.append(contentsOf: changes)
}
} else { } else {
debugLog("Failed to replace \(molecule) in the template model.") debugLog("Failed to replace \(molecule) in the template model.")
} }
@ -289,37 +287,36 @@ import MVMCore
if let originalModel, // We had a prior. if let originalModel, // We had a prior.
let newPageModel = newPageModel as? TemplateModelProtocol, let newPageModel = newPageModel as? TemplateModelProtocol,
originalModel.id != newPageModel.id { originalModel.id != newPageModel.id {
let diffs = newPageModel.deepCompare(against: originalModel) { new, old in // This isn't ready yet. handleNewData for the ListTemplate triggers a row item reset and full rebuild + StackTemplate isn't targeting individual refreshes anyway.
!new.isEqual(to: old) // pageUpdatedModels = originalModel.findAllTheirsNotEqual(against: newPageModel)
} // debugLog("Page molecule updates\n\(pageUpdatedModels)")
debugLog("Page molecule updates\n\(diffs.map {"\($0.mine) vs. \($0.theirs)"}.joined(separator: "\n"))") isFirstRender = true // Instead force a full render whenever there is a page data change.
pageUpdatedModels = diffs.compactMap { $0.theirs as? MoleculeModelProtocol }
} }
let allUpdatedMolecules = isFirstRender ? [] : behaviorUpdatedModels + pageUpdatedModels let allUpdatedMolecules = behaviorUpdatedModels //+ pageUpdatedModels
isFirstRender = false // Notify the manager of new data.
// Warning: Some flows cause table reloads. Until the UI update is decoupled, should be after the updateUI.
manager?.newDataReceived?(in: self)
// Dispatch to decouple execution. First massage data through template classes, then render. // Dispatch to decouple execution. First massage data through template classes, then render.
Task { @MainActor in Task { @MainActor in
if allUpdatedMolecules.isEmpty { if allUpdatedMolecules.isEmpty || isFirstRender {
debugLog("Performing full page render...") debugLog("Performing full page render...")
updateUI() updateUI()
} else { } else {
debugLog("Performing partial render of \(allUpdatedMolecules) molecules...") debugLog("Performing partial render of \(allUpdatedMolecules) molecules...")
updateUI(for: allUpdatedMolecules) updateUI(for: allUpdatedMolecules)
} }
// Notify the manager of new data.
// Warning: Some flows cause table reloads. Until the UI update is decoupled, should be after the updateUI.
manager?.newDataReceived?(in: self)
} }
} }
/// Applies the latest model to the UI. /// Applies the latest model to the UI.
open func updateUI(for molecules: [MoleculeModelProtocol]? = nil) { open func updateUI(for molecules: [MoleculeModelProtocol]? = nil) {
isFirstRender = false
executeBehaviors { (behavior: PageMoleculeTransformationBehavior) in executeBehaviors { (behavior: PageMoleculeTransformationBehavior) in
behavior.willRender(rootMolecules: molecules ?? getRootMolecules(), delegateObjectIVar) behavior.willRender(rootMolecules: molecules ?? getRootMolecules(), delegateObjectIVar)
} }