From fd735b81394c87b7731465b56628084082fe7226 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 22 Oct 2020 11:16:54 -0400 Subject: [PATCH] accessibility and formatting --- .../Atomic/Atoms/Views/LoadImageView.swift | 170 +++++++++++------- .../BGImageHeadlineBodyButton.swift | 1 - .../HeadlineBody.swift | 16 +- 3 files changed, 117 insertions(+), 70 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadImageView.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadImageView.swift index 42267a20..0ad4c16b 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadImageView.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadImageView.swift @@ -6,18 +6,21 @@ // Copyright © 2020 Verizon Wireless. All rights reserved. // -import UIKit @objcMembers open class LoadImageView: View { + //-------------------------------------------------- + // MARK: - Outlets + //-------------------------------------------------- + public let loadingSpinner = MFLoadingSpinner(frame: .zero) public let imageView = MFTransparentGIFView(frame: .zero) + + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public var addSizeConstraintsForAspectRatio = true public var shouldNotifyDelegateOnUpdate = true - var centerX: NSLayoutConstraint? - var centerY: NSLayoutConstraint? - var widthConstraint: NSLayoutConstraint? - var heightConstraint: NSLayoutConstraint? - var loadingSpinnerHeightConstraint: NSLayoutConstraint? // Allows for a view to hardcode which height to use if there is none in the json. var imageWidth: CGFloat? @@ -35,6 +38,25 @@ import UIKit private var containerHelper = ContainerHelper() + open override var accessibilityLabel: String? { + get { imageView.accessibilityLabel } + set { imageView.accessibilityLabel = newValue } + } + + //-------------------------------------------------- + // MARK: - Constraint Properties + //-------------------------------------------------- + + var centerX: NSLayoutConstraint? + var centerY: NSLayoutConstraint? + var widthConstraint: NSLayoutConstraint? + var heightConstraint: NSLayoutConstraint? + var loadingSpinnerHeightConstraint: NSLayoutConstraint? + + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + public init(pinnedEdges edge: UIRectEdge) { edges = edge super.init(frame: .zero) @@ -60,51 +82,24 @@ import UIKit set(with: model, delegateObject, additionalData) } - public func pinEdges(_ edge: UIRectEdge) { - edges = edge - if edge == UIRectEdge.all { - imageView.setContentHuggingPriority(UILayoutPriority.defaultLow, for: NSLayoutConstraint.Axis.horizontal) - imageView.setContentHuggingPriority(UILayoutPriority.defaultLow, for: NSLayoutConstraint.Axis.vertical) - } else { - imageView.setContentHuggingPriority(UILayoutPriority(rawValue: 900), for: NSLayoutConstraint.Axis.horizontal) - imageView.setContentHuggingPriority(UILayoutPriority(rawValue: 900), for: NSLayoutConstraint.Axis.vertical) - } - - if edge.contains(UIRectEdge.top) && edge.contains(UIRectEdge.bottom) { - containerHelper.alignVertical(.fill) - } else if edge.contains(UIRectEdge.top) { - containerHelper.alignVertical(.leading) - } else if edge.contains(UIRectEdge.bottom) { - containerHelper.alignVertical(.trailing) - } else { - containerHelper.alignVertical(.center) - } - - if edge.contains(UIRectEdge.left) && edge.contains(UIRectEdge.right) { - containerHelper.alignHorizontal(.fill) - } else if edge.contains(UIRectEdge.left) { - containerHelper.alignHorizontal(.leading) - } else if edge.contains(UIRectEdge.right) { - containerHelper.alignHorizontal(.trailing) - } else { - containerHelper.alignHorizontal(.center) - } - } + //-------------------------------------------------- + // MARK: - MVMCoreViewProtocol + //-------------------------------------------------- override open func setupView() { super.setupView() - guard subviews.count == 0 else { - return - } + + guard subviews.count == 0 else { return } + clipsToBounds = true - setContentHuggingPriority(UILayoutPriority(rawValue: 950), for: NSLayoutConstraint.Axis.horizontal) - setContentHuggingPriority(UILayoutPriority(rawValue: 950), for: NSLayoutConstraint.Axis.vertical) - + setContentHuggingPriority(UILayoutPriority(rawValue: 950), for: .horizontal) + setContentHuggingPriority(UILayoutPriority(rawValue: 950), for: .vertical) + // Setup image. imageView.translatesAutoresizingMaskIntoConstraints = false; addSubview(imageView) containerHelper.constrainView(imageView) - + // Setup edges constraints pinEdges(edges) @@ -125,8 +120,12 @@ import UIKit } } + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + open func defaultCompletionBlock() -> MVMCoreGetImageBlock { - return {image,gifData,_ in MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in + return { image, gifData,_ in MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in if let image = image { self?.imageView.image = image self?.layoutIfNeeded() @@ -139,9 +138,8 @@ import UIKit open func shouldLoadImage(withName imageName: String?, width: CGFloat) -> Bool { // We should load a new image if there is no current image, the image names are different, the width is different, or we are using a fallback image. - guard let currentWidth = self.currentImageWidth else { - return true - } + guard let currentWidth = self.currentImageWidth else { return true } + return (imageView.image == nil && imageView.animatedImage == nil) || imageName != currentImageName || !MVMCoreGetterUtility.cgfequal(width, currentWidth) || isFallbackImage } @@ -150,22 +148,61 @@ import UIKit if ((imageView.image == nil && imageView.animatedImage == nil) || imageName != currentImageName || isFallbackImage) { return true } + // load new image if the width is different if let oldWidth = self.currentImageWidth, let newWidth = width, !MVMCoreGetterUtility.cgfequal(oldWidth, newWidth) { return true + } else if (self.currentImageWidth == nil) != (width == nil) { return true } + // load new image if the height is different if let oldHeight = self.currentImageHeight, let newHeight = height, !MVMCoreGetterUtility.cgfequal(oldHeight, newHeight) { return true + } else if (self.currentImageHeight == nil) || (height == nil) { return true } + return false } - // MARK: - Constraints + //-------------------------------------------------- + // MARK: - Constraint Methods + //-------------------------------------------------- + + public func pinEdges(_ edge: UIRectEdge) { + edges = edge + + if edge == .all { + imageView.setContentHuggingPriority(.defaultLow, for: .horizontal) + imageView.setContentHuggingPriority(.defaultLow, for: .vertical) + } else { + imageView.setContentHuggingPriority(UILayoutPriority(rawValue: 900), for: .horizontal) + imageView.setContentHuggingPriority(UILayoutPriority(rawValue: 900), for: .vertical) + } + + if edge.contains(.top) && edge.contains(.bottom) { + containerHelper.alignVertical(.fill) + } else if edge.contains(.top) { + containerHelper.alignVertical(.leading) + } else if edge.contains(.bottom) { + containerHelper.alignVertical(.trailing) + } else { + containerHelper.alignVertical(.center) + } + + if edge.contains(.left) && edge.contains(.right) { + containerHelper.alignHorizontal(.fill) + } else if edge.contains(.left) { + containerHelper.alignHorizontal(.leading) + } else if edge.contains(.right) { + containerHelper.alignHorizontal(.trailing) + } else { + containerHelper.alignHorizontal(.center) + } + } func setHeight(_ height: CGFloat) { if let heightConstraint = heightConstraint, MVMCoreGetterUtility.cgfequal(heightConstraint.multiplier, 1) { @@ -187,9 +224,8 @@ import UIKit } func layoutWillChange(width: CGFloat?, height: CGFloat?, size: CGSize?) -> Bool { - guard addSizeConstraintsForAspectRatio else { - return false - } + guard addSizeConstraintsForAspectRatio else { return false } + let widthWillChange = !MVMCoreGetterUtility.cgfequal(widthConstraint?.constant ?? 0, width ?? 0) let heightWillChange = !MVMCoreGetterUtility.cgfequal(heightConstraint?.constant ?? 0, height ?? 0) let sizeWillChange = (width == nil || height == nil) && !(size?.equalTo(imageView.image?.size ?? CGSize.zero) ?? false) @@ -199,11 +235,11 @@ import UIKit // Constrains the image view to be the size provided. Used to size it to the image to fix aspect fit defect. func addConstraints(width: NSNumber?, height: NSNumber?, size: CGSize?) { + widthConstraint?.isActive = false heightConstraint?.isActive = false - guard addSizeConstraintsForAspectRatio else { - return - } + + guard addSizeConstraintsForAspectRatio else { return } if let width = width, let height = height { setHeight(height.cgfloat()) @@ -221,31 +257,40 @@ import UIKit } } + //-------------------------------------------------- + // MARK: - MoleculeViewProtocol + //-------------------------------------------------- + public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { self.delegateObject = delegateObject super.set(with: model, delegateObject, additionalData) - + guard let imageModel = model as? ImageViewModel else { return } + if let accessibilityString = imageModel.accessibilityText { imageView.accessibilityLabel = accessibilityString imageView.accessibilityTraits = .staticText imageView.isAccessibilityElement = true } + let width = imageModel.width ?? imageWidth let height = imageModel.height ?? imageHeight + // For smoother transitions, set constraints that we know immediately. if let width = width, addSizeConstraintsForAspectRatio { setWidth(width) } + if let height = height, addSizeConstraintsForAspectRatio { setHeight(height) } + if shouldLoadImage(withName: imageModel.image, width: width, height: height) { imageView.image = nil imageView.animatedImage = nil loadImage(withName: imageModel.image, format: imageModel.imageFormat, width: width as NSNumber?, height: height as NSNumber?, customFallbackImage: imageModel.fallbackImage, localBundle: imageModel.localBundle) } - + if let contentMode = imageModel.contentMode { imageView.contentMode = contentMode } @@ -260,7 +305,10 @@ import UIKit } } - // MARK: - load functions + //-------------------------------------------------- + // MARK: - Load Methods + //-------------------------------------------------- + public func loadImage(withName imageName: String?, format: String? = nil, width: NSNumber? = nil, height: NSNumber? = nil, customFallbackImage: String? = nil, allowServerParameters: Bool = false, localBundle: Bundle? = nil, completionHandler: MVMCoreGetImageBlock? = nil) { let completionBlock = completionHandler ?? defaultCompletionBlock() @@ -275,7 +323,7 @@ import UIKit let finishedLoadingBlock: MVMCoreGetImageBlock = {[weak self] (image, data, isFallbackImage) in MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in guard let self = self, - let loadingImageName = self.currentImageName, loadingImageName == imageName else { return } + let loadingImageName = self.currentImageName, loadingImageName == imageName else { return } self.isFallbackImage = isFallbackImage self.loadingSpinner.pause() let layoutWillChange = self.shouldNotifyDelegateOnUpdate ? self.layoutWillChange(width: self.currentImageWidth, height: self.currentImageHeight, size: image?.size) : false @@ -298,12 +346,12 @@ import UIKit } public func loadCroppedImage(withName imageName: - String?, width: NSNumber?, height: NSNumber?, cropRect: CGRect, flipImage: Bool, customFallbackImage: String?) { + String?, width: NSNumber?, height: NSNumber?, cropRect: CGRect, flipImage: Bool, customFallbackImage: String?) { MVMCoreDispatchUtility.performBlock(onMainThread: { [unowned self] in self.currentImageName = imageName self.loadingSpinner.resumeSpinnerAfterDelay() self.loadingSpinnerHeightConstraint?.constant = self.spinnerHeight - + MVMCoreCache.shared()?.getCroppedImage(imageName, useWidth: width != nil, widthForS7: width?.intValue ?? 0, useHeight: height != nil, heightForS7: height?.intValue ?? 0, finalRect: cropRect, flipImage: flipImage, localFallbackImageName: customFallbackImage ?? MVMCoreUIUtility.localizedImageName("fallback"), completionHandler: { [weak self] (image, data, isFallBackImage) in MVMCoreDispatchUtility.performBlock(onMainThread: { guard let image = image, let loadingImageName = self?.currentImageName, loadingImageName == imageName else { @@ -327,7 +375,7 @@ import UIKit public func loadImage(withName imageName: String?) { loadImage(withName: imageName, format: nil, width: nil, height: nil, customFallbackImage: nil, completionHandler: defaultCompletionBlock()) } - + public func loadImage(withName imageName: String?, width: NSNumber?) { loadImage(withName: imageName, format: nil, width: width, height: nil, customFallbackImage: nil, completionHandler: defaultCompletionBlock()) } diff --git a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/BGImageHeadlineBodyButton.swift b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/BGImageHeadlineBodyButton.swift index bac1b1c2..3c6fd2bd 100644 --- a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/BGImageHeadlineBodyButton.swift +++ b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/BGImageHeadlineBodyButton.swift @@ -135,7 +135,6 @@ } open override func accessibilityActivate() -> Bool { - return button.accessibilityActivate() } } diff --git a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBody.swift b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBody.swift index 48d6c129..d111d1c5 100644 --- a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBody.swift +++ b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBody.swift @@ -79,7 +79,7 @@ open class HeadlineBody: View { } //-------------------------------------------------- - // MARK: - Setup + // MARK: - MVMCoreViewProtocol //-------------------------------------------------- open override func setupView() { @@ -123,6 +123,13 @@ open class HeadlineBody: View { view.bottomAnchor.constraint(equalTo: messageLabel.bottomAnchor).isActive = true } + open override func updateView(_ size: CGFloat) { + super.updateView(size) + headlineLabel.updateView(size) + messageLabel.updateView(size) + setSpacing() + } + //-------------------------------------------------- // MARK: - Constraining //-------------------------------------------------- @@ -139,13 +146,6 @@ open class HeadlineBody: View { // MARK: - MoleculeViewProtocol //-------------------------------------------------- - open override func updateView(_ size: CGFloat) { - super.updateView(size) - headlineLabel.updateView(size) - messageLabel.updateView(size) - setSpacing() - } - public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { return 58 }