From af20b0a8a46d8cb6cbf1d150df3d371a4d21192d Mon Sep 17 00:00:00 2001 From: "Xinlei(Ryan) Pan" Date: Fri, 24 Jan 2020 10:41:04 -0500 Subject: [PATCH 1/2] remove entryfieldcontainer for odd behavior --- MVMCoreUI.xcodeproj/project.pbxproj | 4 - .../Views/EntryFieldContainer.swift | 285 ------------------ 2 files changed, 289 deletions(-) delete mode 100644 MVMCoreUI/Containers/Views/EntryFieldContainer.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index f395d21b..21e90897 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -86,7 +86,6 @@ 0AA33B3A2398524F0067DD0F /* Toggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AA33B392398524F0067DD0F /* Toggle.swift */; }; 0ABD136D237CAD1E0081388D /* DateDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ABD136C237CAD1E0081388D /* DateDropdownEntryField.swift */; }; 0ABD1371237DB0450081388D /* ItemDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */; }; - 0ACDF26B23DA0AC2002044B2 /* EntryFieldContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ACDF26A23DA0AC2002044B2 /* EntryFieldContainer.swift */; }; 0AE14F64238315D2005417F8 /* TextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE14F63238315D2005417F8 /* TextField.swift */; }; 31BE15CB23D8924D00452370 /* CheckboxLabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31BE15C923D8924C00452370 /* CheckboxLabelModel.swift */; }; 31BE15CC23D8924D00452370 /* CheckboxModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31BE15CA23D8924C00452370 /* CheckboxModel.swift */; }; @@ -389,7 +388,6 @@ 0AA33B392398524F0067DD0F /* Toggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toggle.swift; sourceTree = ""; }; 0ABD136C237CAD1E0081388D /* DateDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateDropdownEntryField.swift; sourceTree = ""; }; 0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemDropdownEntryField.swift; sourceTree = ""; }; - 0ACDF26A23DA0AC2002044B2 /* EntryFieldContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntryFieldContainer.swift; sourceTree = ""; }; 0AE14F63238315D2005417F8 /* TextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = ""; }; 31BE15C923D8924C00452370 /* CheckboxLabelModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheckboxLabelModel.swift; sourceTree = ""; }; 31BE15CA23D8924C00452370 /* CheckboxModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheckboxModel.swift; sourceTree = ""; }; @@ -702,7 +700,6 @@ isa = PBXGroup; children = ( D29E28DE23D740FC00ACEA85 /* Container */, - 0ACDF26A23DA0AC2002044B2 /* EntryFieldContainer.swift */, 014AA72123C501E2006F3E93 /* MoleculeContainerModel.swift */, D2FB151A23A2B65B00C20E10 /* MoleculeContainer.swift */, ); @@ -1624,7 +1621,6 @@ 017BEB7F23676E870024EF95 /* MoleculeObjectMapping.swift in Sources */, D274CA332236A78900B01B62 /* FooterView.swift in Sources */, D29DF2BF21E7BEA4003B2FB9 /* MVMCoreUITabBarPageControlViewController.m in Sources */, - 0ACDF26B23DA0AC2002044B2 /* EntryFieldContainer.swift in Sources */, 014AA72423C501E2006F3E93 /* MoleculeContainerModel.swift in Sources */, D29DF28321E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.m in Sources */, 011B58F223A2AE2C0085F53C /* DropDownListItemModel.swift in Sources */, diff --git a/MVMCoreUI/Containers/Views/EntryFieldContainer.swift b/MVMCoreUI/Containers/Views/EntryFieldContainer.swift deleted file mode 100644 index 96a51a8f..00000000 --- a/MVMCoreUI/Containers/Views/EntryFieldContainer.swift +++ /dev/null @@ -1,285 +0,0 @@ -// -// EntryFieldContainer.swift -// MVMCoreUI -// -// Created by Kevin Christiano on 11/12/19. -// Copyright © 2019 Verizon Wireless. All rights reserved. -// - -import UIKit - - -@objcMembers open class EntryFieldContainer: View { - //-------------------------------------------------- - // MARK: - Drawing Properties - //-------------------------------------------------- - - /// The bottom border line. Height is dynamic based on scenario. - public var bottomBar: CAShapeLayer? = { - let layer = CAShapeLayer() - layer.backgroundColor = UIColor.black.cgColor - layer.drawsAsynchronously = true - layer.anchorPoint = CGPoint(x: 0.5, y: 1.0); - return layer - }() - - /// Total control over the drawn top, bottom, left and right borders. - public var disableAllBorders = false { - didSet { - bottomBar?.isHidden = disableAllBorders - } - } - - private(set) var fieldState: FieldState = .original { - didSet (oldState) { - // Will not update if new state is the same as old. - if fieldState != oldState { - DispatchQueue.main.async { [weak self] in - guard let self = self else { return } - - self.fieldState.setStateUI(for: self) - } - } - } - } - - /// Determines if the top, left, and right borders should be drawn. - private var hideBorders = false - - public var borderStrokeColor: UIColor = .mfSilver() - private var borderPath: UIBezierPath = UIBezierPath() - - //-------------------------------------------------- - // MARK: - Property Observers - //-------------------------------------------------- - - private var _isEnabled: Bool = true - private var _showError: Bool = false - private var _isLocked: Bool = false - private var _isSelected: Bool = false - - public var isEnabled: Bool { - get { return _isEnabled } - set (enabled) { - - _isEnabled = enabled - _isLocked = false - _isSelected = false - _showError = false - - fieldState = enabled ? .original : .disabled - } - } - - public var showError: Bool { - get { return _showError } - set (error) { - - _showError = error - _isEnabled = true - _isLocked = false - _isSelected = false - - fieldState = error ? .error : .original - } - } - - public var isLocked: Bool { - get { return _isLocked } - set (locked) { - - _isLocked = locked - _isEnabled = true - _isSelected = false - _showError = false - - fieldState = locked ? .locked : .original - } - } - - public var isSelected: Bool { - get { return _isSelected } - set (selected) { - - _isSelected = selected - _isLocked = false - _isEnabled = true - - if _showError { - fieldState = selected ? .selectedError : .error - } else { - fieldState = selected ? .selected : .original - } - } - } - - //-------------------------------------------------- - // MARK: - Delegate - //-------------------------------------------------- - - /// Holds reference to delegateObject to inform molecular tableView of an update. - weak var delegateObject: MVMCoreUIDelegateObject? - - //-------------------------------------------------- - // MARK: - Lifecycle - //-------------------------------------------------- - - open override func layoutSubviews() { - super.layoutSubviews() - - refreshUI(bottomBarSize: showError ? 4 : 1) - } - - open override func updateView(_ size: CGFloat) { - super.updateView(size) - - refreshUI() - } - - /// This handles the top, left, and right border lines. - open override func draw(_ rect: CGRect) { - super.draw(rect) - - borderPath.removeAllPoints() - - if !disableAllBorders && !hideBorders { - // Brings the other half of the line inside the view to prevent cropping. - let origin = bounds.origin - let size = frame.size - let insetLean: CGFloat = 0.5 - borderPath.lineWidth = 1 - - borderPath.move(to: CGPoint(x: origin.x + insetLean, y: origin.y + size.height)) - borderPath.addLine(to: CGPoint(x: origin.x + insetLean, y: origin.y + insetLean)) - borderPath.addLine(to: CGPoint(x: origin.x + size.width - insetLean, y: origin.y + insetLean)) - borderPath.addLine(to: CGPoint(x: origin.x + size.width - insetLean, y: origin.y + size.height)) - - borderStrokeColor.setStroke() - borderPath.stroke() - } - } - - override open func setupView() { - super.setupView() - - isAccessibilityElement = false - isOpaque = false - - if let bottomBar = bottomBar { - layer.addSublayer(bottomBar) - } - } - - //-------------------------------------------------- - // MARK: - Draw States - //-------------------------------------------------- - - public enum FieldState { - case original - case error - case selectedError - case selected - case locked - case disabled - - public func setStateUI(for formField: EntryFieldContainer) { - - switch self { - case .original: - formField.originalUI() - - case .error: - formField.errorUI() - - case .selectedError: - formField.selectedErrorUI() - - case .selected: - formField.selectedUI() - - case .locked: - formField.lockedUI() - - case .disabled: - formField.disabledUI() - } - } - } - - open func originalUI() { - - isUserInteractionEnabled = true - hideBorders = false - borderStrokeColor = .mfSilver() - bottomBar?.backgroundColor = UIColor.black.cgColor - refreshUI(bottomBarSize: 1) - } - - open func errorUI() { - - isUserInteractionEnabled = true - hideBorders = false - borderStrokeColor = .mfPumpkin() - bottomBar?.backgroundColor = UIColor.mfPumpkin().cgColor - refreshUI(bottomBarSize: 4) - } - - open func selectedErrorUI() { - - isUserInteractionEnabled = true - hideBorders = false - borderStrokeColor = .black - bottomBar?.backgroundColor = UIColor.mfPumpkin().cgColor - refreshUI(bottomBarSize: 4) - } - - open func selectedUI() { - - isUserInteractionEnabled = true - hideBorders = false - borderStrokeColor = .black - bottomBar?.backgroundColor = UIColor.black.cgColor - refreshUI(bottomBarSize: 1) - } - - open func lockedUI() { - - isUserInteractionEnabled = false - hideBorders = true - borderStrokeColor = .clear - bottomBar?.backgroundColor = UIColor.clear.cgColor - refreshUI(bottomBarSize: 1) - } - - open func disabledUI() { - - isUserInteractionEnabled = false - hideBorders = false - borderStrokeColor = .mfSilver() - bottomBar?.backgroundColor = UIColor.mfSilver().cgColor - refreshUI(bottomBarSize: 1) - } - - open func refreshUI(bottomBarSize: CGFloat? = nil) { - - if !disableAllBorders { - let size: CGFloat = bottomBarSize ?? (showError ? 4 : 1) - bottomBar?.frame = CGRect(x: 0, y: bounds.height - size, width: bounds.width, height: size) - - delegateObject?.moleculeDelegate?.moleculeLayoutUpdated(self) - setNeedsDisplay() - layoutIfNeeded() - } - } -} - -// MARK:- MVMCoreUIMoleculeViewProtocol -extension EntryFieldContainer { - - override open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - self.delegateObject = delegateObject - - guard let dictionary = json, !dictionary.isEmpty else { return } - } -} From 5e4f976a1cbf75ec2bb8be9384328ed7eb326eed Mon Sep 17 00:00:00 2001 From: "Xinlei(Ryan) Pan" Date: Fri, 24 Jan 2020 10:42:13 -0500 Subject: [PATCH 2/2] re add entry field container for fixing odd behavior --- MVMCoreUI.xcodeproj/project.pbxproj | 4 + .../Views/EntryFieldContainer.swift | 293 ++++++++++++++++++ 2 files changed, 297 insertions(+) create mode 100644 MVMCoreUI/Containers/Views/EntryFieldContainer.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 21e90897..aec00c53 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -89,6 +89,7 @@ 0AE14F64238315D2005417F8 /* TextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE14F63238315D2005417F8 /* TextField.swift */; }; 31BE15CB23D8924D00452370 /* CheckboxLabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31BE15C923D8924C00452370 /* CheckboxLabelModel.swift */; }; 31BE15CC23D8924D00452370 /* CheckboxModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31BE15CA23D8924C00452370 /* CheckboxModel.swift */; }; + 9432A79F23DB47BA00719041 /* EntryFieldContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9432A79E23DB47BA00719041 /* EntryFieldContainer.swift */; }; 943784F5236B77BB006A1E82 /* GraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943784F3236B77BB006A1E82 /* GraphView.swift */; }; 943784F6236B77BB006A1E82 /* GraphViewAnimationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943784F4236B77BB006A1E82 /* GraphViewAnimationHandler.swift */; }; 9445890C2385BCE300DE9FD4 /* ProgressBarModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9445890B2385BCE300DE9FD4 /* ProgressBarModel.swift */; }; @@ -392,6 +393,7 @@ 31BE15C923D8924C00452370 /* CheckboxLabelModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheckboxLabelModel.swift; sourceTree = ""; }; 31BE15CA23D8924C00452370 /* CheckboxModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheckboxModel.swift; sourceTree = ""; }; 9402C34F23A2CEA3004B974C /* LeftRightLabelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LeftRightLabelModel.swift; sourceTree = ""; }; + 9432A79E23DB47BA00719041 /* EntryFieldContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntryFieldContainer.swift; sourceTree = ""; }; 943784F3236B77BB006A1E82 /* GraphView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphView.swift; sourceTree = ""; }; 943784F4236B77BB006A1E82 /* GraphViewAnimationHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphViewAnimationHandler.swift; sourceTree = ""; }; 9445890B2385BCE300DE9FD4 /* ProgressBarModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBarModel.swift; sourceTree = ""; }; @@ -699,6 +701,7 @@ 0ABD1369237B18EE0081388D /* Views */ = { isa = PBXGroup; children = ( + 9432A79E23DB47BA00719041 /* EntryFieldContainer.swift */, D29E28DE23D740FC00ACEA85 /* Container */, 014AA72123C501E2006F3E93 /* MoleculeContainerModel.swift */, D2FB151A23A2B65B00C20E10 /* MoleculeContainer.swift */, @@ -1666,6 +1669,7 @@ D28A839323CE828900DFE4FC /* HeadlineBodyCaretLinkImageModel.swift in Sources */, D29770C821F7C4AE00B2F0D0 /* TopLabelsView.m in Sources */, D260105F23D0BFFC00764D80 /* StackItem.swift in Sources */, + 9432A79F23DB47BA00719041 /* EntryFieldContainer.swift in Sources */, 01EB369323609801006832FA /* HeaderModel.swift in Sources */, D2E1FADF2268B8E700AEFD8C /* ThreeLayerTableViewController.swift in Sources */, 0A21DB83235DFBC500C160A2 /* MdnEntryField.swift in Sources */, diff --git a/MVMCoreUI/Containers/Views/EntryFieldContainer.swift b/MVMCoreUI/Containers/Views/EntryFieldContainer.swift new file mode 100644 index 00000000..3f80006a --- /dev/null +++ b/MVMCoreUI/Containers/Views/EntryFieldContainer.swift @@ -0,0 +1,293 @@ +// +// EntryFieldContainer.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 11/12/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + + +@objcMembers open class EntryFieldContainer: View { + //-------------------------------------------------- + // MARK: - Drawing Properties + //-------------------------------------------------- + + /// The bottom border line. Height is dynamic based on scenario. + public var bottomBar: CAShapeLayer? = { + let layer = CAShapeLayer() + layer.backgroundColor = UIColor.black.cgColor + layer.drawsAsynchronously = true + layer.anchorPoint = CGPoint(x: 0.5, y: 1.0); + return layer + }() + + /// Total control over the drawn top, bottom, left and right borders. + public var disableAllBorders = false { + didSet { + bottomBar?.isHidden = disableAllBorders + } + } + + private(set) var fieldState: FieldState = .original { + didSet (oldState) { + // Will not update if new state is the same as old. + if fieldState != oldState { + DispatchQueue.main.async { [weak self] in + guard let self = self else { return } + + self.fieldState.setStateUI(for: self) + } + } + } + } + + /// Determines if the top, left, and right borders should be drawn. + private var hideBorders = false + + public var borderStrokeColor: UIColor = .mfSilver() + private var borderPath: UIBezierPath = UIBezierPath() + + //-------------------------------------------------- + // MARK: - Property Observers + //-------------------------------------------------- + + private var _isEnabled: Bool = true + private var _showError: Bool = false + private var _isLocked: Bool = false + private var _isSelected: Bool = false + + public var isEnabled: Bool { + get { return _isEnabled } + set (enabled) { + + _isEnabled = enabled + _isLocked = false + _isSelected = false + _showError = false + + fieldState = enabled ? .original : .disabled + } + } + + public var showError: Bool { + get { return _showError } + set (error) { + + _showError = error + _isEnabled = true + _isLocked = false + _isSelected = false + + fieldState = error ? .error : .original + } + } + + public var isLocked: Bool { + get { return _isLocked } + set (locked) { + + _isLocked = locked + _isEnabled = true + _isSelected = false + _showError = false + + fieldState = locked ? .locked : .original + } + } + + public var isSelected: Bool { + get { return _isSelected } + set (selected) { + + _isSelected = selected + _isLocked = false + _isEnabled = true + + if _showError { + fieldState = selected ? .selectedError : .error + } else { + fieldState = selected ? .selected : .original + } + } + } + + //-------------------------------------------------- + // MARK: - Delegate + //-------------------------------------------------- + + /// Holds reference to delegateObject to inform molecular tableView of an update. + var delegateObject: MVMCoreUIDelegateObject? + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + + open override func layoutSubviews() { + super.layoutSubviews() + + refreshUI(bottomBarSize: showError ? 4 : 1) + } + + open override func updateView(_ size: CGFloat) { + super.updateView(size) + + refreshUI() + } + + /// This handles the top, left, and right border lines. + open override func draw(_ rect: CGRect) { + super.draw(rect) + + borderPath.removeAllPoints() + + if !disableAllBorders && !hideBorders { + // Brings the other half of the line inside the view to prevent cropping. + let origin = bounds.origin + let size = frame.size + let insetLean: CGFloat = 0.5 + borderPath.lineWidth = 1 + + borderPath.move(to: CGPoint(x: origin.x + insetLean, y: origin.y + size.height)) + borderPath.addLine(to: CGPoint(x: origin.x + insetLean, y: origin.y + insetLean)) + borderPath.addLine(to: CGPoint(x: origin.x + size.width - insetLean, y: origin.y + insetLean)) + borderPath.addLine(to: CGPoint(x: origin.x + size.width - insetLean, y: origin.y + size.height)) + + borderStrokeColor.setStroke() + borderPath.stroke() + } + } + + override open func setupView() { + super.setupView() + + isAccessibilityElement = false + isOpaque = false + + if let bottomBar = bottomBar { + layer.addSublayer(bottomBar) + } + } + + //-------------------------------------------------- + // MARK: - Draw States + //-------------------------------------------------- + + public enum FieldState { + case original + case error + case selectedError + case selected + case locked + case disabled + + public func setStateUI(for formField: EntryFieldContainer) { + + switch self { + case .original: + formField.originalUI() + + case .error: + formField.errorUI() + + case .selectedError: + formField.selectedErrorUI() + + case .selected: + formField.selectedUI() + + case .locked: + formField.lockedUI() + + case .disabled: + formField.disabledUI() + } + } + } + + open func originalUI() { + + isUserInteractionEnabled = true + hideBorders = false + borderStrokeColor = .mfSilver() + bottomBar?.backgroundColor = UIColor.black.cgColor + refreshUI(bottomBarSize: 1) + } + + open func errorUI() { + + isUserInteractionEnabled = true + hideBorders = false + borderStrokeColor = .mfPumpkin() + bottomBar?.backgroundColor = UIColor.mfPumpkin().cgColor + refreshUI(bottomBarSize: 4) + } + + open func selectedErrorUI() { + + isUserInteractionEnabled = true + hideBorders = false + borderStrokeColor = .black + bottomBar?.backgroundColor = UIColor.mfPumpkin().cgColor + refreshUI(bottomBarSize: 4) + } + + open func selectedUI() { + + isUserInteractionEnabled = true + hideBorders = false + borderStrokeColor = .black + bottomBar?.backgroundColor = UIColor.black.cgColor + refreshUI(bottomBarSize: 1) + } + + open func lockedUI() { + + isUserInteractionEnabled = false + hideBorders = true + borderStrokeColor = .clear + bottomBar?.backgroundColor = UIColor.clear.cgColor + refreshUI(bottomBarSize: 1) + } + + open func disabledUI() { + + isUserInteractionEnabled = false + hideBorders = false + borderStrokeColor = .mfSilver() + bottomBar?.backgroundColor = UIColor.mfSilver().cgColor + refreshUI(bottomBarSize: 1) + } + + open func refreshUI(bottomBarSize: CGFloat? = nil) { + + if !disableAllBorders { + let size: CGFloat = bottomBarSize ?? (showError ? 4 : 1) + bottomBar?.frame = CGRect(x: 0, y: bounds.height - size, width: bounds.width, height: size) + + delegateObject?.moleculeDelegate?.moleculeLayoutUpdated(self) + setNeedsDisplay() + layoutIfNeeded() + } + } + + //-------------------------------------------------- + // MARK: - MVMCoreUIMoleculeViewProtocol + //-------------------------------------------------- + + open override func setWithModel(_ model: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + super.setWithModel(model, delegateObject, additionalData) + self.delegateObject = delegateObject + } +} + +extension EntryFieldContainer { + + override open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + self.delegateObject = delegateObject + + guard let dictionary = json, !dictionary.isEmpty else { return } + } +}