From 725d4e3cd72bf613a1fcb7d9d8d39f1b81b731ea Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Fri, 14 Jun 2024 13:49:18 -0400 Subject: [PATCH 1/9] Digital PCT265 defect CXTDT-573370: Expose VDS bundle helper in MVMCoreUI. --- MVMCoreUI/Utility/MVMCoreUIUtility.h | 3 +++ MVMCoreUI/Utility/MVMCoreUIUtility.m | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/MVMCoreUI/Utility/MVMCoreUIUtility.h b/MVMCoreUI/Utility/MVMCoreUIUtility.h index c6959723..daba0310 100644 --- a/MVMCoreUI/Utility/MVMCoreUIUtility.h +++ b/MVMCoreUI/Utility/MVMCoreUIUtility.h @@ -22,6 +22,9 @@ NS_ASSUME_NONNULL_BEGIN // The bundle for this framework + (nullable NSBundle *)bundleForMVMCoreUI; +/// The bundle for the VDS frameowrk. Handy for accessing VDS resources such as fonts. ++ (nullable NSBundle *)bundleForVDS; + // Returns the hardcoded string from the string file. + (nullable NSString *)hardcodedStringWithKey:(nonnull NSString *)key; diff --git a/MVMCoreUI/Utility/MVMCoreUIUtility.m b/MVMCoreUI/Utility/MVMCoreUIUtility.m index ad7366df..c8e57888 100644 --- a/MVMCoreUI/Utility/MVMCoreUIUtility.m +++ b/MVMCoreUI/Utility/MVMCoreUIUtility.m @@ -22,6 +22,10 @@ return [NSBundle bundleWithIdentifier:@"com.vzw.MVMCoreUI"]; } ++ (nullable NSBundle *)bundleForVDS { + return [NSBundle bundleWithIdentifier:@"com.vzw.vds"]; +} + + (nullable NSString *)hardcodedStringWithKey:(nonnull NSString *)key { // Redirect key with relevant module. return [MVMCoreGetterUtility hardcodedStringWithKey:key bundle:[MVMCoreUIUtility bundleForMVMCoreUI]]; From 19f08dca7993b2a69efea6f790f1e69cb4dcb5a5 Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Fri, 14 Jun 2024 14:15:00 -0400 Subject: [PATCH 2/9] Digital PCT265 defect CXTDT-573370: Code review. Matt's genious. --- MVMCoreUI/Utility/MVMCoreUIUtility.h | 2 +- MVMCoreUI/Utility/MVMCoreUIUtility.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Utility/MVMCoreUIUtility.h b/MVMCoreUI/Utility/MVMCoreUIUtility.h index daba0310..12c1aa34 100644 --- a/MVMCoreUI/Utility/MVMCoreUIUtility.h +++ b/MVMCoreUI/Utility/MVMCoreUIUtility.h @@ -23,7 +23,7 @@ NS_ASSUME_NONNULL_BEGIN + (nullable NSBundle *)bundleForMVMCoreUI; /// The bundle for the VDS frameowrk. Handy for accessing VDS resources such as fonts. -+ (nullable NSBundle *)bundleForVDS; ++ (nullable NSBundle *)bundleForFonts; // Returns the hardcoded string from the string file. + (nullable NSString *)hardcodedStringWithKey:(nonnull NSString *)key; diff --git a/MVMCoreUI/Utility/MVMCoreUIUtility.m b/MVMCoreUI/Utility/MVMCoreUIUtility.m index c8e57888..e725114d 100644 --- a/MVMCoreUI/Utility/MVMCoreUIUtility.m +++ b/MVMCoreUI/Utility/MVMCoreUIUtility.m @@ -22,7 +22,7 @@ return [NSBundle bundleWithIdentifier:@"com.vzw.MVMCoreUI"]; } -+ (nullable NSBundle *)bundleForVDS { ++ (nullable NSBundle *)bundleForFonts { return [NSBundle bundleWithIdentifier:@"com.vzw.vds"]; } From be797aaee246d51f1da0a8be9f64f91f7cb98d82 Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Mon, 17 Jun 2024 19:21:19 -0400 Subject: [PATCH 3/9] Digital PCT265 defect DE307-687: Re-log all analytics on page state return. --- .../ReplaceableMoleculeBehaviorModel.swift | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/MVMCoreUI/Behaviors/ReplaceableMoleculeBehaviorModel.swift b/MVMCoreUI/Behaviors/ReplaceableMoleculeBehaviorModel.swift index 9cbf85ed..8b624a7b 100644 --- a/MVMCoreUI/Behaviors/ReplaceableMoleculeBehaviorModel.swift +++ b/MVMCoreUI/Behaviors/ReplaceableMoleculeBehaviorModel.swift @@ -20,7 +20,7 @@ public class ReplaceableMoleculeBehaviorModel: PageBehaviorModelProtocol { } } -public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior, CoreLogging { +public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior, PageVisibilityBehavior, CoreLogging { public var loggingPrefix: String { "\(self) \(ObjectIdentifier(self).hashValue) \(moleculeIds.prefix(3)) \(moleculeIds.count > 3 ? "+ \(moleculeIds.count - 3) more" : ""):\n" @@ -30,6 +30,8 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior, Co String(describing: Self.self) } + var hasPreviouslyBeenShown = false + var previouslyReplacedIds = Set() var moleculeIds: [String] public var modulesToListenFor: [String] private var observingForResponses: NSObjectProtocol? @@ -75,7 +77,7 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior, Co return rootMolecule } debugLog("top replacing \(rootMolecule) with \(updatedMolecule)") - logUpdated(molecule: updatedMolecule) + logUpdated(moleculeId: updatedMolecule.id) changeList.append(updatedMolecule) return updatedMolecule } @@ -92,7 +94,7 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior, Co return } debugLog("deep replacing \(replacedMolecule) with \(newMolecule)") - logUpdated(molecule: newMolecule) + logUpdated(moleculeId: newMolecule.id) changeList.append(newMolecule) } } catch { @@ -111,15 +113,28 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior, Co return hasReplacement ? updatedRootMolecules : nil } - private func logUpdated(molecule: MoleculeModelProtocol) { - guard let module: [AnyHashable: Any] = delegateObject?.moleculeDelegate?.getModuleWithName(molecule.id), + private func logUpdated(moleculeId: String) { + guard let module: [AnyHashable: Any] = delegateObject?.moleculeDelegate?.getModuleWithName(moleculeId), let viewController = delegateObject?.moleculeDelegate as? MVMCoreViewControllerProtocol else { - debugLog("Missing the originating module \(molecule.id) creating this molecule!") + debugLog("Missing the originating module \(moleculeId) creating this molecule!") return } + previouslyReplacedIds.insert(moleculeId) MVMCoreUILoggingHandler.shared()?.defaultLogPageUpdate(forController: viewController, from: module) } + public func onPageShown(_ delegateObject: MVMCoreUIDelegateObject?) { + guard hasPreviouslyBeenShown else { + // Skip first replacement build handled in onPageNew. (Pulled and reported from cache.) + hasPreviouslyBeenShown = true + return + } + debugLog("Page reshown. Resend replaced molecule analytics for: \(previouslyReplacedIds)") + previouslyReplacedIds.forEach { id in + logUpdated(moleculeId: id) + } + } + deinit { debugLog("deinit") } From 10c63a52b972da383980778dd30cc16a37ca0c97 Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Mon, 17 Jun 2024 19:43:47 -0400 Subject: [PATCH 4/9] Digital PCT265 defect DE307-687: Slightly better logging clarity, making sure the base page is logged before the module counterparts. --- .../ReplaceableMoleculeBehaviorModel.swift | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/MVMCoreUI/Behaviors/ReplaceableMoleculeBehaviorModel.swift b/MVMCoreUI/Behaviors/ReplaceableMoleculeBehaviorModel.swift index 8b624a7b..c35a5d19 100644 --- a/MVMCoreUI/Behaviors/ReplaceableMoleculeBehaviorModel.swift +++ b/MVMCoreUI/Behaviors/ReplaceableMoleculeBehaviorModel.swift @@ -30,7 +30,7 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior, Pa String(describing: Self.self) } - var hasPreviouslyBeenShown = false + var isPageShowing = false var previouslyReplacedIds = Set() var moleculeIds: [String] public var modulesToListenFor: [String] @@ -120,21 +120,22 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior, Pa return } previouslyReplacedIds.insert(moleculeId) + guard isPageShowing else { return } // Page has not been made visible yet. (Pulled and replaced from cache on load or background update.) Hold reporting until onPageShown. MVMCoreUILoggingHandler.shared()?.defaultLogPageUpdate(forController: viewController, from: module) } public func onPageShown(_ delegateObject: MVMCoreUIDelegateObject?) { - guard hasPreviouslyBeenShown else { - // Skip first replacement build handled in onPageNew. (Pulled and reported from cache.) - hasPreviouslyBeenShown = true - return - } - debugLog("Page reshown. Resend replaced molecule analytics for: \(previouslyReplacedIds)") + isPageShowing = true + debugLog("Page shown. Send molecule analytics for: \(previouslyReplacedIds)") previouslyReplacedIds.forEach { id in logUpdated(moleculeId: id) } } + public func onPageHidden(_ delegateObject: MVMCoreUIDelegateObject?) { + isPageShowing = false + } + deinit { debugLog("deinit") } From 451758f96d311c98b85b1625802ba9282b1327f5 Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Wed, 19 Jun 2024 14:52:33 -0400 Subject: [PATCH 5/9] Restore table reload to ensure table is synced to model. --- MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift index d7c60545..ee44218e 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift @@ -56,14 +56,14 @@ open class ThreeLayerTableViewController: ProgrammaticTableViewController, Rotor } open override func updateUI(for molecules: [MoleculeModelProtocol]? = nil) { - let isFirstRender = self.isFirstRender super.updateUI(for: molecules) guard molecules == nil else { return } createViewForTableHeader() createViewForTableFooter() - // Reloading the table is handled in updateViews. + // Reloading the table is handled in updateViews, however, update views is on a separate rendering task than the current thread. The table render needs to be bound and settled to the new model before others put in additional update requests. + tableView.reloadData() } override open func viewDidLoad() { From efa99033e9a443f52d85d06aba3434a4f5e342b4 Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Wed, 19 Jun 2024 15:30:03 -0400 Subject: [PATCH 6/9] Digital PCT265 story CXTDT-574791: Prevent additional reload tables in updateView. --- MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift index ee44218e..4bd889bd 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift @@ -52,7 +52,9 @@ open class ThreeLayerTableViewController: ProgrammaticTableViewController, Rotor bottomView.updateView(width) showFooter(width) } - tableView.reloadData() + tableView.visibleCells.forEach { cell in + (cell as? MVMCoreViewProtocol)?.updateView(width) + } } open override func updateUI(for molecules: [MoleculeModelProtocol]? = nil) { From 41548b84342d6c38329583add3787b035d3e0490 Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Thu, 20 Jun 2024 16:44:58 -0400 Subject: [PATCH 7/9] Digital PCT265 defect CXTDT-531317: Give the default page type for those that send an empty string. --- MVMCoreUI/Atomic/Templates/BaseTemplateModel.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MVMCoreUI/Atomic/Templates/BaseTemplateModel.swift b/MVMCoreUI/Atomic/Templates/BaseTemplateModel.swift index da57579d..ea4e0d88 100644 --- a/MVMCoreUI/Atomic/Templates/BaseTemplateModel.swift +++ b/MVMCoreUI/Atomic/Templates/BaseTemplateModel.swift @@ -83,6 +83,9 @@ import Foundation let typeContainer = try decoder.container(keyedBy: CodingKeys.self) if let defaultPageType = Self.defaultPageType() { pageType = try typeContainer.decodeIfPresent(String.self, forKey: .pageType) ?? defaultPageType + if pageType.isEmpty { + pageType = defaultPageType + } } else { pageType = try typeContainer.decode(String.self, forKey: .pageType) } From adb415f72c3cbb2564c5f27a3fee8bfdad7c972e Mon Sep 17 00:00:00 2001 From: "Subramaniam, Ramya" Date: Fri, 21 Jun 2024 12:17:48 +0530 Subject: [PATCH 8/9] Making the view nil to prevent dangling contrainst --- MVMCoreUI/Atomic/Organisms/Carousel/Carousel.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/MVMCoreUI/Atomic/Organisms/Carousel/Carousel.swift b/MVMCoreUI/Atomic/Organisms/Carousel/Carousel.swift index 585944bf..3ef117da 100644 --- a/MVMCoreUI/Atomic/Organisms/Carousel/Carousel.swift +++ b/MVMCoreUI/Atomic/Organisms/Carousel/Carousel.swift @@ -307,6 +307,7 @@ open class Carousel: View { pagingView?.removeFromSuperview() bottomPin?.isActive = false + pagingView = nil guard var pagingView = view else { bottomPin = bottomAnchor.constraint(equalTo: collectionView.bottomAnchor) From 3108dcdafc931fc81de9b2a4dbf59f359a16ddab Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 21 Jun 2024 14:11:20 -0500 Subject: [PATCH 9/9] refactored out code that is now in VDS.Label Signed-off-by: Matt Bruce --- .../Atomic/Atoms/Views/Label/Label.swift | 34 ++----------------- 1 file changed, 2 insertions(+), 32 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift index fa71def6..605f2e8a 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift @@ -364,8 +364,8 @@ extension Label { public static func boundingRect(forCharacterRange range: NSRange, in label: Label) -> CGRect { guard let abstractContainer = label.abstractTextContainer() else { return CGRect() } - let textContainer = abstractContainer.0 - let layoutManager = abstractContainer.1 + let textContainer = abstractContainer.textContainer + let layoutManager = abstractContainer.layoutManager var glyphRange = NSRange() @@ -374,36 +374,6 @@ extension Label { return layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer) } - - /** - Provides a text container and layout manager of how the text would appear on screen. - They are used in tandem to derive low-level TextKit results of the label. - */ - public func abstractTextContainer() -> (NSTextContainer, NSLayoutManager, NSTextStorage)? { - - // Must configure the attributed string to translate what would appear on screen to accurately analyze. - guard let attributedText = attributedText else { return nil } - - let paragraph = NSMutableParagraphStyle() - paragraph.alignment = textAlignment - - let stagedAttributedString = NSMutableAttributedString(attributedString: attributedText) - stagedAttributedString.addAttributes([NSAttributedString.Key.paragraphStyle: paragraph], range: NSRange(location: 0, length: attributedText.string.count)) - - let textStorage = NSTextStorage(attributedString: stagedAttributedString) - let layoutManager = NSLayoutManager() - let textContainer = NSTextContainer(size: .zero) - - layoutManager.addTextContainer(textContainer) - textStorage.addLayoutManager(layoutManager) - - textContainer.lineFragmentPadding = 0.0 - textContainer.lineBreakMode = lineBreakMode - textContainer.maximumNumberOfLines = numberOfLines - textContainer.size = bounds.size - - return (textContainer, layoutManager, textStorage) - } } // MARK: - Atomization