Merge branch 'bugfix/layout_accessibility_fx' into 'develop'
accessibility and formatting update See merge request BPHV_MIPS/mvm_core_ui!579
This commit is contained in:
commit
51ee84bee0
@ -51,6 +51,7 @@ import UIKit
|
|||||||
guard let model = model as? LinkModel else { return }
|
guard let model = model as? LinkModel else { return }
|
||||||
|
|
||||||
setTitle(model.title, for: .normal)
|
setTitle(model.title, for: .normal)
|
||||||
|
accessibilityLabel = model.title
|
||||||
setTitleColor((model.inverted ? model.enabledColor_inverted : model.enabledColor).uiColor, for: .normal)
|
setTitleColor((model.inverted ? model.enabledColor_inverted : model.enabledColor).uiColor, for: .normal)
|
||||||
setTitleColor((model.inverted ? model.disabledColor_inverted : model.disabledColor).uiColor, for: .disabled)
|
setTitleColor((model.inverted ? model.disabledColor_inverted : model.disabledColor).uiColor, for: .disabled)
|
||||||
isEnabled = model.enabled
|
isEnabled = model.enabled
|
||||||
|
|||||||
@ -6,9 +6,12 @@
|
|||||||
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
@objcMembers public class ImageViewModel: MoleculeModelProtocol {
|
@objcMembers public class ImageViewModel: MoleculeModelProtocol {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public static var identifier: String = "image"
|
public static var identifier: String = "image"
|
||||||
public var backgroundColor: Color?
|
public var backgroundColor: Color?
|
||||||
public var moleculeName: String = ImageViewModel.identifier
|
public var moleculeName: String = ImageViewModel.identifier
|
||||||
@ -23,6 +26,10 @@ import Foundation
|
|||||||
public var cornerRadius: CGFloat?
|
public var cornerRadius: CGFloat?
|
||||||
public var clipsImage: Bool?
|
public var clipsImage: Bool?
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Initializer
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public init(image: String, imageFormat: String? = nil, width: CGFloat? = nil, height: CGFloat? = nil) {
|
public init(image: String, imageFormat: String? = nil, width: CGFloat? = nil, height: CGFloat? = nil) {
|
||||||
self.image = image
|
self.image = image
|
||||||
self.imageFormat = imageFormat
|
self.imageFormat = imageFormat
|
||||||
@ -30,6 +37,10 @@ import Foundation
|
|||||||
self.height = height
|
self.height = height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Keys
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case moleculeName
|
case moleculeName
|
||||||
case backgroundColor
|
case backgroundColor
|
||||||
|
|||||||
@ -6,18 +6,21 @@
|
|||||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
@objcMembers open class LoadImageView: View {
|
@objcMembers open class LoadImageView: View {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Outlets
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public let loadingSpinner = MFLoadingSpinner(frame: .zero)
|
public let loadingSpinner = MFLoadingSpinner(frame: .zero)
|
||||||
public let imageView = MFTransparentGIFView(frame: .zero)
|
public let imageView = MFTransparentGIFView(frame: .zero)
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public var addSizeConstraintsForAspectRatio = true
|
public var addSizeConstraintsForAspectRatio = true
|
||||||
public var shouldNotifyDelegateOnUpdate = 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.
|
// Allows for a view to hardcode which height to use if there is none in the json.
|
||||||
var imageWidth: CGFloat?
|
var imageWidth: CGFloat?
|
||||||
@ -35,6 +38,25 @@ import UIKit
|
|||||||
|
|
||||||
private var containerHelper = ContainerHelper()
|
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) {
|
public init(pinnedEdges edge: UIRectEdge) {
|
||||||
edges = edge
|
edges = edge
|
||||||
super.init(frame: .zero)
|
super.init(frame: .zero)
|
||||||
@ -60,51 +82,24 @@ import UIKit
|
|||||||
set(with: model, delegateObject, additionalData)
|
set(with: model, delegateObject, additionalData)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func pinEdges(_ edge: UIRectEdge) {
|
//--------------------------------------------------
|
||||||
edges = edge
|
// MARK: - MVMCoreViewProtocol
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override open func setupView() {
|
override open func setupView() {
|
||||||
super.setupView()
|
super.setupView()
|
||||||
guard subviews.count == 0 else {
|
|
||||||
return
|
guard subviews.count == 0 else { return }
|
||||||
}
|
|
||||||
clipsToBounds = true
|
clipsToBounds = true
|
||||||
setContentHuggingPriority(UILayoutPriority(rawValue: 950), for: NSLayoutConstraint.Axis.horizontal)
|
setContentHuggingPriority(UILayoutPriority(rawValue: 950), for: .horizontal)
|
||||||
setContentHuggingPriority(UILayoutPriority(rawValue: 950), for: NSLayoutConstraint.Axis.vertical)
|
setContentHuggingPriority(UILayoutPriority(rawValue: 950), for: .vertical)
|
||||||
|
|
||||||
// Setup image.
|
// Setup image.
|
||||||
imageView.translatesAutoresizingMaskIntoConstraints = false;
|
imageView.translatesAutoresizingMaskIntoConstraints = false;
|
||||||
addSubview(imageView)
|
addSubview(imageView)
|
||||||
containerHelper.constrainView(imageView)
|
containerHelper.constrainView(imageView)
|
||||||
|
|
||||||
// Setup edges constraints
|
// Setup edges constraints
|
||||||
pinEdges(edges)
|
pinEdges(edges)
|
||||||
|
|
||||||
@ -125,8 +120,12 @@ import UIKit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Methods
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
open func defaultCompletionBlock() -> MVMCoreGetImageBlock {
|
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 {
|
if let image = image {
|
||||||
self?.imageView.image = image
|
self?.imageView.image = image
|
||||||
self?.layoutIfNeeded()
|
self?.layoutIfNeeded()
|
||||||
@ -139,9 +138,8 @@ import UIKit
|
|||||||
|
|
||||||
open func shouldLoadImage(withName imageName: String?, width: CGFloat) -> Bool {
|
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.
|
// 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 {
|
guard let currentWidth = self.currentImageWidth else { return true }
|
||||||
return true
|
|
||||||
}
|
|
||||||
return (imageView.image == nil && imageView.animatedImage == nil) || imageName != currentImageName || !MVMCoreGetterUtility.cgfequal(width, currentWidth) || isFallbackImage
|
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) {
|
if ((imageView.image == nil && imageView.animatedImage == nil) || imageName != currentImageName || isFallbackImage) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// load new image if the width is different
|
// load new image if the width is different
|
||||||
if let oldWidth = self.currentImageWidth, let newWidth = width, !MVMCoreGetterUtility.cgfequal(oldWidth, newWidth) {
|
if let oldWidth = self.currentImageWidth, let newWidth = width, !MVMCoreGetterUtility.cgfequal(oldWidth, newWidth) {
|
||||||
return true
|
return true
|
||||||
|
|
||||||
} else if (self.currentImageWidth == nil) != (width == nil) {
|
} else if (self.currentImageWidth == nil) != (width == nil) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// load new image if the height is different
|
// load new image if the height is different
|
||||||
if let oldHeight = self.currentImageHeight, let newHeight = height, !MVMCoreGetterUtility.cgfequal(oldHeight, newHeight) {
|
if let oldHeight = self.currentImageHeight, let newHeight = height, !MVMCoreGetterUtility.cgfequal(oldHeight, newHeight) {
|
||||||
return true
|
return true
|
||||||
|
|
||||||
} else if (self.currentImageHeight == nil) || (height == nil) {
|
} else if (self.currentImageHeight == nil) || (height == nil) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
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) {
|
func setHeight(_ height: CGFloat) {
|
||||||
if let heightConstraint = heightConstraint, MVMCoreGetterUtility.cgfequal(heightConstraint.multiplier, 1) {
|
if let heightConstraint = heightConstraint, MVMCoreGetterUtility.cgfequal(heightConstraint.multiplier, 1) {
|
||||||
@ -187,9 +224,8 @@ import UIKit
|
|||||||
}
|
}
|
||||||
|
|
||||||
func layoutWillChange(width: CGFloat?, height: CGFloat?, size: CGSize?) -> Bool {
|
func layoutWillChange(width: CGFloat?, height: CGFloat?, size: CGSize?) -> Bool {
|
||||||
guard addSizeConstraintsForAspectRatio else {
|
guard addSizeConstraintsForAspectRatio else { return false }
|
||||||
return false
|
|
||||||
}
|
|
||||||
let widthWillChange = !MVMCoreGetterUtility.cgfequal(widthConstraint?.constant ?? 0, width ?? 0)
|
let widthWillChange = !MVMCoreGetterUtility.cgfequal(widthConstraint?.constant ?? 0, width ?? 0)
|
||||||
let heightWillChange = !MVMCoreGetterUtility.cgfequal(heightConstraint?.constant ?? 0, height ?? 0)
|
let heightWillChange = !MVMCoreGetterUtility.cgfequal(heightConstraint?.constant ?? 0, height ?? 0)
|
||||||
let sizeWillChange = (width == nil || height == nil) && !(size?.equalTo(imageView.image?.size ?? CGSize.zero) ?? false)
|
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.
|
// 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?) {
|
func addConstraints(width: NSNumber?, height: NSNumber?, size: CGSize?) {
|
||||||
|
|
||||||
widthConstraint?.isActive = false
|
widthConstraint?.isActive = false
|
||||||
heightConstraint?.isActive = false
|
heightConstraint?.isActive = false
|
||||||
guard addSizeConstraintsForAspectRatio else {
|
|
||||||
return
|
guard addSizeConstraintsForAspectRatio else { return }
|
||||||
}
|
|
||||||
|
|
||||||
if let width = width, let height = height {
|
if let width = width, let height = height {
|
||||||
setHeight(height.cgfloat())
|
setHeight(height.cgfloat())
|
||||||
@ -221,31 +257,40 @@ import UIKit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - MoleculeViewProtocol
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
self.delegateObject = delegateObject
|
self.delegateObject = delegateObject
|
||||||
super.set(with: model, delegateObject, additionalData)
|
super.set(with: model, delegateObject, additionalData)
|
||||||
|
|
||||||
guard let imageModel = model as? ImageViewModel else { return }
|
guard let imageModel = model as? ImageViewModel else { return }
|
||||||
|
|
||||||
if let accessibilityString = imageModel.accessibilityText {
|
if let accessibilityString = imageModel.accessibilityText {
|
||||||
imageView.accessibilityLabel = accessibilityString
|
imageView.accessibilityLabel = accessibilityString
|
||||||
imageView.accessibilityTraits = .staticText
|
imageView.accessibilityTraits = .staticText
|
||||||
imageView.isAccessibilityElement = true
|
imageView.isAccessibilityElement = true
|
||||||
}
|
}
|
||||||
|
|
||||||
let width = imageModel.width ?? imageWidth
|
let width = imageModel.width ?? imageWidth
|
||||||
let height = imageModel.height ?? imageHeight
|
let height = imageModel.height ?? imageHeight
|
||||||
|
|
||||||
// For smoother transitions, set constraints that we know immediately.
|
// For smoother transitions, set constraints that we know immediately.
|
||||||
if let width = width, addSizeConstraintsForAspectRatio {
|
if let width = width, addSizeConstraintsForAspectRatio {
|
||||||
setWidth(width)
|
setWidth(width)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let height = height, addSizeConstraintsForAspectRatio {
|
if let height = height, addSizeConstraintsForAspectRatio {
|
||||||
setHeight(height)
|
setHeight(height)
|
||||||
}
|
}
|
||||||
|
|
||||||
if shouldLoadImage(withName: imageModel.image, width: width, height: height) {
|
if shouldLoadImage(withName: imageModel.image, width: width, height: height) {
|
||||||
imageView.image = nil
|
imageView.image = nil
|
||||||
imageView.animatedImage = 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)
|
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 {
|
if let contentMode = imageModel.contentMode {
|
||||||
imageView.contentMode = 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) {
|
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()
|
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
|
let finishedLoadingBlock: MVMCoreGetImageBlock = {[weak self] (image, data, isFallbackImage) in MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in
|
||||||
guard let self = self,
|
guard let self = self,
|
||||||
let loadingImageName = self.currentImageName, loadingImageName == imageName else { return }
|
let loadingImageName = self.currentImageName, loadingImageName == imageName else { return }
|
||||||
self.isFallbackImage = isFallbackImage
|
self.isFallbackImage = isFallbackImage
|
||||||
self.loadingSpinner.pause()
|
self.loadingSpinner.pause()
|
||||||
let layoutWillChange = self.shouldNotifyDelegateOnUpdate ? self.layoutWillChange(width: self.currentImageWidth, height: self.currentImageHeight, size: image?.size) : false
|
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:
|
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
|
MVMCoreDispatchUtility.performBlock(onMainThread: { [unowned self] in
|
||||||
self.currentImageName = imageName
|
self.currentImageName = imageName
|
||||||
self.loadingSpinner.resumeSpinnerAfterDelay()
|
self.loadingSpinner.resumeSpinnerAfterDelay()
|
||||||
self.loadingSpinnerHeightConstraint?.constant = self.spinnerHeight
|
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
|
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: {
|
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
||||||
guard let image = image, let loadingImageName = self?.currentImageName, loadingImageName == imageName else {
|
guard let image = image, let loadingImageName = self?.currentImageName, loadingImageName == imageName else {
|
||||||
@ -327,7 +375,7 @@ import UIKit
|
|||||||
public func loadImage(withName imageName: String?) {
|
public func loadImage(withName imageName: String?) {
|
||||||
loadImage(withName: imageName, format: nil, width: nil, height: nil, customFallbackImage: nil, completionHandler: defaultCompletionBlock())
|
loadImage(withName: imageName, format: nil, width: nil, height: nil, customFallbackImage: nil, completionHandler: defaultCompletionBlock())
|
||||||
}
|
}
|
||||||
|
|
||||||
public func loadImage(withName imageName: String?, width: NSNumber?) {
|
public func loadImage(withName imageName: String?, width: NSNumber?) {
|
||||||
loadImage(withName: imageName, format: nil, width: width, height: nil, customFallbackImage: nil, completionHandler: defaultCompletionBlock())
|
loadImage(withName: imageName, format: nil, width: width, height: nil, customFallbackImage: nil, completionHandler: defaultCompletionBlock())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,8 +6,6 @@
|
|||||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
|
|
||||||
@objcMembers open class ListDeviceComplexButtonSmall: TableViewCell {
|
@objcMembers open class ListDeviceComplexButtonSmall: TableViewCell {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -19,7 +17,7 @@ import Foundation
|
|||||||
public let headline = Label(fontStyle: .BoldTitleMedium)
|
public let headline = Label(fontStyle: .BoldTitleMedium)
|
||||||
public let body = Label(fontStyle: .RegularBodySmall)
|
public let body = Label(fontStyle: .RegularBodySmall)
|
||||||
public let body2 = Label(fontStyle: .RegularBodySmall)
|
public let body2 = Label(fontStyle: .RegularBodySmall)
|
||||||
public let button = PillButton(frame: .zero)
|
public let button = PillButton()
|
||||||
public let rightImageView = LoadImageView()
|
public let rightImageView = LoadImageView()
|
||||||
public var stack: Stack<StackModel>
|
public var stack: Stack<StackModel>
|
||||||
|
|
||||||
@ -99,6 +97,7 @@ import Foundation
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
func getAccessibilityMessage() -> String? {
|
func getAccessibilityMessage() -> String? {
|
||||||
|
|
||||||
var message = ""
|
var message = ""
|
||||||
if let eyebrowText = eyebrow.text, !eyebrowText.isEmpty {
|
if let eyebrowText = eyebrow.text, !eyebrowText.isEmpty {
|
||||||
message += eyebrowText + ", "
|
message += eyebrowText + ", "
|
||||||
@ -119,10 +118,12 @@ import Foundation
|
|||||||
if let rightImageViewText = rightImageView.imageView.accessibilityLabel, !rightImageViewText.isEmpty {
|
if let rightImageViewText = rightImageView.imageView.accessibilityLabel, !rightImageViewText.isEmpty {
|
||||||
message += rightImageViewText
|
message += rightImageViewText
|
||||||
}
|
}
|
||||||
|
|
||||||
return message.count > 0 ? message : nil
|
return message.count > 0 ? message : nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateAccessibilityLabel() {
|
func updateAccessibilityLabel() {
|
||||||
|
|
||||||
if let accessoryView = accessoryView {
|
if let accessoryView = accessoryView {
|
||||||
// Both caret and button. Read all content on caret.
|
// Both caret and button. Read all content on caret.
|
||||||
isAccessibilityElement = false
|
isAccessibilityElement = false
|
||||||
|
|||||||
@ -8,14 +8,22 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
|
||||||
public class MoleculeHeaderView: MoleculeContainer {
|
public class MoleculeHeaderView: MoleculeContainer {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
var line = Line()
|
var line = Line()
|
||||||
|
|
||||||
var headerModel: MoleculeHeaderModel? {
|
var headerModel: MoleculeHeaderModel? {
|
||||||
get { return model as? MoleculeHeaderModel }
|
get { return model as? MoleculeHeaderModel }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
// MARK: - MVMCoreViewProtocol
|
// MARK: - MVMCoreViewProtocol
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
open override func updateView(_ size: CGFloat) {
|
open override func updateView(_ size: CGFloat) {
|
||||||
super.updateView(size)
|
super.updateView(size)
|
||||||
line.updateView(size)
|
line.updateView(size)
|
||||||
@ -30,16 +38,16 @@ public class MoleculeHeaderView: MoleculeContainer {
|
|||||||
NSLayoutConstraint.pinViewRight(toSuperview: line, useMargins: true, constant: 0).isActive = true
|
NSLayoutConstraint.pinViewRight(toSuperview: line, useMargins: true, constant: 0).isActive = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - MoleculeViewProtocol
|
|
||||||
open override func reset() {
|
open override func reset() {
|
||||||
super.reset()
|
super.reset()
|
||||||
line.setStyle(.heavy)
|
line.setStyle(.heavy)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - MoleculeViewProtocol
|
|
||||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
super.set(with: model, delegateObject, additionalData)
|
super.set(with: model, delegateObject, additionalData)
|
||||||
|
|
||||||
guard let headerModel = headerModel else { return }
|
guard let headerModel = headerModel else { return }
|
||||||
|
|
||||||
if let lineModel = headerModel.line {
|
if let lineModel = headerModel.line {
|
||||||
line.set(with: lineModel, delegateObject, additionalData)
|
line.set(with: lineModel, delegateObject, additionalData)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
|
||||||
@objcMembers open class TwoButtonView: View, MVMCoreUIViewConstrainingProtocol {
|
@objcMembers open class TwoButtonView: View, MVMCoreUIViewConstrainingProtocol {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
@ -44,6 +45,7 @@ import UIKit
|
|||||||
super.setupView()
|
super.setupView()
|
||||||
|
|
||||||
stack.translatesAutoresizingMaskIntoConstraints = false
|
stack.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
isAccessibilityElement = false
|
||||||
addSubview(stack)
|
addSubview(stack)
|
||||||
stack.addArrangedSubview(secondaryButton)
|
stack.addArrangedSubview(secondaryButton)
|
||||||
stack.addArrangedSubview(primaryButton)
|
stack.addArrangedSubview(primaryButton)
|
||||||
@ -68,6 +70,8 @@ import UIKit
|
|||||||
if secondaryButton.superview != nil {
|
if secondaryButton.superview != nil {
|
||||||
equalWidthConstraint?.isActive = true
|
equalWidthConstraint?.isActive = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
primaryButton.isAccessibilityElement = true
|
||||||
}
|
}
|
||||||
|
|
||||||
public func showSecondaryButton() {
|
public func showSecondaryButton() {
|
||||||
@ -80,6 +84,8 @@ import UIKit
|
|||||||
if primaryButton.superview != nil {
|
if primaryButton.superview != nil {
|
||||||
equalWidthConstraint?.isActive = true
|
equalWidthConstraint?.isActive = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
secondaryButton.isAccessibilityElement = true
|
||||||
}
|
}
|
||||||
|
|
||||||
public func hidePrimaryButton() {
|
public func hidePrimaryButton() {
|
||||||
@ -89,6 +95,7 @@ import UIKit
|
|||||||
primaryButton.isHidden = true
|
primaryButton.isHidden = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
primaryButton.isAccessibilityElement = false
|
||||||
equalWidthConstraint?.isActive = false
|
equalWidthConstraint?.isActive = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,6 +106,7 @@ import UIKit
|
|||||||
secondaryButton.isHidden = true
|
secondaryButton.isHidden = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
secondaryButton.isAccessibilityElement = false
|
||||||
equalWidthConstraint?.isActive = false
|
equalWidthConstraint?.isActive = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,9 +6,12 @@
|
|||||||
// Copyright © 2019 Suresh, Kamlesh. All rights reserved.
|
// Copyright © 2019 Suresh, Kamlesh. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
@objcMembers public class MoleculeStackItemModel: MoleculeContainerModel, StackItemModelProtocol {
|
@objcMembers public class MoleculeStackItemModel: MoleculeContainerModel, StackItemModelProtocol {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public override class var identifier: String {
|
public override class var identifier: String {
|
||||||
return "stackItem"
|
return "stackItem"
|
||||||
}
|
}
|
||||||
@ -16,6 +19,10 @@ import Foundation
|
|||||||
public var percent: Int?
|
public var percent: Int?
|
||||||
public var gone: Bool = false
|
public var gone: Bool = false
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Keys
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case spacing
|
case spacing
|
||||||
case percent
|
case percent
|
||||||
@ -23,10 +30,18 @@ import Foundation
|
|||||||
case moleculeName
|
case moleculeName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Initializer
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public override init(with moleculeModel: MoleculeModelProtocol) {
|
public override init(with moleculeModel: MoleculeModelProtocol) {
|
||||||
super.init(with: moleculeModel)
|
super.init(with: moleculeModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Codec
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
spacing = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .spacing)
|
spacing = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .spacing)
|
||||||
@ -36,7 +51,7 @@ import Foundation
|
|||||||
}
|
}
|
||||||
try super.init(from: decoder)
|
try super.init(from: decoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func encode(to encoder: Encoder) throws {
|
public override func encode(to encoder: Encoder) throws {
|
||||||
try super.encode(to: encoder)
|
try super.encode(to: encoder)
|
||||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|||||||
@ -6,7 +6,6 @@
|
|||||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
open class StackItem: Container {
|
open class StackItem: Container {
|
||||||
var stackItemModel: StackItemModel? {
|
var stackItemModel: StackItemModel? {
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
|
||||||
open class MoleculeContainer: Container {
|
open class MoleculeContainer: Container {
|
||||||
|
|
||||||
/// Can be overriden to change how the molecule is added to the hierarchy.
|
/// Can be overriden to change how the molecule is added to the hierarchy.
|
||||||
@ -29,26 +30,32 @@ open class MoleculeContainer: Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override static func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
public override static func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
||||||
|
|
||||||
guard let containerModel = model as? MoleculeContainerModelProtocol,
|
guard let containerModel = model as? MoleculeContainerModelProtocol,
|
||||||
let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(containerModel.molecule),
|
let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(containerModel.molecule),
|
||||||
let moleculeName = moleculeClass.nameForReuse(with: containerModel.molecule, delegateObject) else {
|
let moleculeName = moleculeClass.nameForReuse(with: containerModel.molecule, delegateObject)
|
||||||
return "\(model.moleculeName)<>"
|
else { return "\(model.moleculeName)<>" }
|
||||||
}
|
|
||||||
return "\(model.moleculeName)<\(moleculeName)>"
|
return "\(model.moleculeName)<\(moleculeName)>"
|
||||||
}
|
}
|
||||||
|
|
||||||
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||||
|
|
||||||
guard let containerModel = model as? MoleculeContainerModelProtocol else { return 0 }
|
guard let containerModel = model as? MoleculeContainerModelProtocol else { return 0 }
|
||||||
|
|
||||||
guard let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(containerModel.molecule),
|
guard let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(containerModel.molecule),
|
||||||
let moleculeHeight = moleculeClass.estimatedHeight(with: containerModel.molecule, delegateObject) else {
|
let moleculeHeight = moleculeClass.estimatedHeight(with: containerModel.molecule, delegateObject)
|
||||||
return (containerModel.topPadding ?? 0) + (containerModel.bottomPadding ?? 0)
|
else { return (containerModel.topPadding ?? 0) + (containerModel.bottomPadding ?? 0) }
|
||||||
}
|
|
||||||
return moleculeHeight + (containerModel.topPadding ?? 0) + (containerModel.bottomPadding ?? 0)
|
return moleculeHeight + (containerModel.topPadding ?? 0) + (containerModel.bottomPadding ?? 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
public override class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
|
public override class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
|
||||||
|
|
||||||
guard let containerModel = model as? MoleculeContainerModelProtocol,
|
guard let containerModel = model as? MoleculeContainerModelProtocol,
|
||||||
let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(containerModel.molecule) else { return nil }
|
let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(containerModel.molecule)
|
||||||
|
else { return nil }
|
||||||
|
|
||||||
return moleculeClass.requiredModules(with: containerModel.molecule, delegateObject, error: error)
|
return moleculeClass.requiredModules(with: containerModel.molecule, delegateObject, error: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,82 +6,135 @@
|
|||||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
@objcMembers public class BGImageHeadlineBodyButton: Container {
|
@objcMembers public class BGImageHeadlineBodyButton: Container {
|
||||||
let headlineBody = HeadlineBody(frame: .zero)
|
//--------------------------------------------------
|
||||||
let button = PillButton(frame: .zero)
|
// MARK: - Outlets
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
let headlineBody = HeadlineBody()
|
||||||
|
let button = PillButton()
|
||||||
let backgroundImageView = LoadImageView(pinnedEdges: .all)
|
let backgroundImageView = LoadImageView(pinnedEdges: .all)
|
||||||
let maxWidth: CGFloat = 350.0
|
|
||||||
static let heightConstant: CGFloat = 320.0
|
//--------------------------------------------------
|
||||||
|
// MARK: - Property
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
let maxWidth: CGFloat = 350
|
||||||
|
static let heightConstant: CGFloat = 320
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Constraints
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
var heightConstraint: NSLayoutConstraint?
|
var heightConstraint: NSLayoutConstraint?
|
||||||
|
|
||||||
// MARK: - MVMCoreViewProtocol
|
//--------------------------------------------------
|
||||||
open override func updateView(_ size: CGFloat) {
|
// MARK: - Setup
|
||||||
super.updateView(size)
|
//--------------------------------------------------
|
||||||
headlineBody.updateView(size)
|
|
||||||
button.updateView(size)
|
|
||||||
backgroundImageView.updateView(size)
|
|
||||||
backgroundImageView.pinEdges(.all)
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func setupView() {
|
open override func setupView() {
|
||||||
super.setupView()
|
super.setupView()
|
||||||
|
|
||||||
heightConstraint = heightAnchor.constraint(equalToConstant: Self.heightConstant)
|
heightConstraint = heightAnchor.constraint(equalToConstant: Self.heightConstant)
|
||||||
heightConstraint?.isActive = true
|
heightConstraint?.isActive = true
|
||||||
|
|
||||||
backgroundImageView.addSizeConstraintsForAspectRatio = true
|
backgroundImageView.addSizeConstraintsForAspectRatio = true
|
||||||
|
|
||||||
let container = MVMCoreUICommonViewsUtility.commonView()
|
let container = MVMCoreUICommonViewsUtility.commonView()
|
||||||
addAndContain(container)
|
addAndContain(container)
|
||||||
|
|
||||||
container.addSubview(headlineBody)
|
container.addSubview(headlineBody)
|
||||||
container.addSubview(button)
|
container.addSubview(button)
|
||||||
|
|
||||||
//Headline view
|
headlineBody.leadingAnchor.constraint(equalTo: container.leadingAnchor).isActive = true
|
||||||
headlineBody.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 0).isActive = true
|
headlineBody.topAnchor.constraint(equalTo: container.topAnchor).isActive = true
|
||||||
headlineBody.topAnchor.constraint(equalTo: container.topAnchor, constant: 0).isActive = true
|
|
||||||
|
|
||||||
let headLineBodyWidth = headlineBody.widthAnchor.constraint(equalTo: container.widthAnchor, multiplier: 0.67)
|
let headLineBodyWidth = headlineBody.widthAnchor.constraint(equalTo: container.widthAnchor, multiplier: 0.67)
|
||||||
headLineBodyWidth.priority = UILayoutPriority(rawValue: 999)
|
headLineBodyWidth.priority = UILayoutPriority(rawValue: 999)
|
||||||
headLineBodyWidth.isActive = true
|
headLineBodyWidth.isActive = true
|
||||||
headlineBody.widthAnchor.constraint(lessThanOrEqualToConstant: maxWidth).isActive = true
|
headlineBody.widthAnchor.constraint(lessThanOrEqualToConstant: maxWidth).isActive = true
|
||||||
|
|
||||||
//Caret view
|
|
||||||
button.translatesAutoresizingMaskIntoConstraints = false
|
button.translatesAutoresizingMaskIntoConstraints = false
|
||||||
button.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 0).isActive = true
|
button.leadingAnchor.constraint(equalTo: container.leadingAnchor).isActive = true
|
||||||
container.bottomAnchor.constraint(greaterThanOrEqualTo: button.bottomAnchor, constant: 0).isActive = true
|
container.bottomAnchor.constraint(greaterThanOrEqualTo: button.bottomAnchor).isActive = true
|
||||||
|
|
||||||
button.topAnchor.constraint(equalTo: headlineBody.bottomAnchor, constant: PaddingDefault).isActive = true
|
button.topAnchor.constraint(equalTo: headlineBody.bottomAnchor, constant: PaddingDefault).isActive = true
|
||||||
|
|
||||||
//Background image view
|
|
||||||
backgroundImageView.translatesAutoresizingMaskIntoConstraints = false
|
backgroundImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
backgroundImageView.imageView.contentMode = .scaleAspectFill
|
backgroundImageView.imageView.contentMode = .scaleAspectFill
|
||||||
backgroundImageView.pinEdges(.all)
|
backgroundImageView.pinEdges(.all)
|
||||||
addSubview(backgroundImageView)
|
addSubview(backgroundImageView)
|
||||||
NSLayoutConstraint.constraintPinSubview(toSuperview: backgroundImageView)
|
NSLayoutConstraint.constraintPinSubview(toSuperview: backgroundImageView)
|
||||||
sendSubviewToBack(backgroundImageView)
|
sendSubviewToBack(backgroundImageView)
|
||||||
}
|
|
||||||
|
|
||||||
|
isAccessibilityElement = true
|
||||||
|
accessibilityHint = button.accessibilityHint
|
||||||
|
accessibilityTraits = button.accessibilityTraits
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
// MARK: - MoleculeViewProtocol
|
// MARK: - MoleculeViewProtocol
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open override func updateView(_ size: CGFloat) {
|
||||||
|
super.updateView(size)
|
||||||
|
headlineBody.updateView(size)
|
||||||
|
button.updateView(size)
|
||||||
|
backgroundImageView.updateView(size)
|
||||||
|
backgroundImageView.pinEdges(.all)
|
||||||
|
}
|
||||||
|
|
||||||
open override func reset() {
|
open override func reset() {
|
||||||
super.reset()
|
super.reset()
|
||||||
headlineBody.reset()
|
headlineBody.reset()
|
||||||
backgroundImageView.reset()
|
backgroundImageView.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK:- MoleculeViewProtocol
|
|
||||||
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||||
return 320
|
return 320
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
|
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
super.set(with: model, delegateObject, additionalData)
|
super.set(with: model, delegateObject, additionalData)
|
||||||
|
|
||||||
guard let model = model as? BGImageHeadlineBodyButtonModel else { return }
|
guard let model = model as? BGImageHeadlineBodyButtonModel else { return }
|
||||||
|
|
||||||
headlineBody.set(with: model.headlineBody, delegateObject, additionalData)
|
headlineBody.set(with: model.headlineBody, delegateObject, additionalData)
|
||||||
button.setOptional(with: model.button, delegateObject, additionalData)
|
button.setOptional(with: model.button, delegateObject, additionalData)
|
||||||
button.isHidden = model.button == nil
|
button.isHidden = model.button == nil
|
||||||
backgroundImageView.set(with: model.image, delegateObject, additionalData)
|
backgroundImageView.set(with: model.image, delegateObject, additionalData)
|
||||||
backgroundImageView.pinEdges(.all)
|
backgroundImageView.pinEdges(.all)
|
||||||
|
updateAccessibilityLabel()
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------
|
||||||
|
// MARK: - Accessibility
|
||||||
|
//----------------------------------------------------
|
||||||
|
|
||||||
|
func updateAccessibilityLabel() {
|
||||||
|
|
||||||
|
var message = ""
|
||||||
|
|
||||||
|
if let headline = headlineBody.headlineLabel.text, !headline.isEmpty {
|
||||||
|
message += headline + ", "
|
||||||
|
}
|
||||||
|
|
||||||
|
if let body = headlineBody.messageLabel.text, !body.isEmpty {
|
||||||
|
message += body + ", "
|
||||||
|
}
|
||||||
|
|
||||||
|
if let backgroundImageText = backgroundImageView.accessibilityLabel, !backgroundImageText.isEmpty {
|
||||||
|
message += backgroundImageText + ", "
|
||||||
|
}
|
||||||
|
|
||||||
|
if let buttonLabel = button.accessibilityLabel, !buttonLabel.isEmpty {
|
||||||
|
message += buttonLabel
|
||||||
|
}
|
||||||
|
|
||||||
|
accessibilityLabel = message
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func accessibilityActivate() -> Bool {
|
||||||
|
return button.accessibilityActivate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,42 +6,62 @@
|
|||||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
public class BGImageHeadlineBodyButtonModel: ContainerModel, MoleculeModelProtocol {
|
public class BGImageHeadlineBodyButtonModel: ContainerModel, MoleculeModelProtocol {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public static var identifier: String = "bgImageHeadlineBodyButton"
|
public static var identifier: String = "bgImageHeadlineBodyButton"
|
||||||
public var backgroundColor: Color?
|
public var backgroundColor: Color?
|
||||||
public var button: ButtonModel?
|
public var button: ButtonModel?
|
||||||
public var headlineBody: HeadlineBodyModel
|
public var headlineBody: HeadlineBodyModel
|
||||||
public var image: ImageViewModel
|
public var image: ImageViewModel
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Initializer
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
init(headlineBody: HeadlineBodyModel, image: ImageViewModel) {
|
init(headlineBody: HeadlineBodyModel, image: ImageViewModel) {
|
||||||
self.headlineBody = headlineBody
|
self.headlineBody = headlineBody
|
||||||
self.image = image
|
self.image = image
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Defaults to set
|
//--------------------------------------------------
|
||||||
|
// MARK: - Defaults
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public override func setDefaults() {
|
public override func setDefaults() {
|
||||||
|
|
||||||
if useHorizontalMargins == nil {
|
if useHorizontalMargins == nil {
|
||||||
useHorizontalMargins = true
|
useHorizontalMargins = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if useVerticalMargins == nil {
|
if useVerticalMargins == nil {
|
||||||
useVerticalMargins = true
|
useVerticalMargins = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if topPadding == nil {
|
if topPadding == nil {
|
||||||
topPadding = PaddingDefault
|
topPadding = PaddingDefault
|
||||||
}
|
}
|
||||||
|
|
||||||
if bottomPadding == nil {
|
if bottomPadding == nil {
|
||||||
bottomPadding = PaddingDefault
|
bottomPadding = PaddingDefault
|
||||||
}
|
}
|
||||||
|
|
||||||
if image.height == nil {
|
if image.height == nil {
|
||||||
image.height = BGImageHeadlineBodyButton.heightConstant
|
image.height = BGImageHeadlineBodyButton.heightConstant
|
||||||
}
|
}
|
||||||
|
|
||||||
button?.size = .tiny
|
button?.size = .tiny
|
||||||
button?.style = .secondary
|
button?.style = .secondary
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Keys
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case moleculeName
|
case moleculeName
|
||||||
case backgroundColor
|
case backgroundColor
|
||||||
@ -49,7 +69,11 @@ public class BGImageHeadlineBodyButtonModel: ContainerModel, MoleculeModelProtoc
|
|||||||
case image
|
case image
|
||||||
case button
|
case button
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Codec
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||||
@ -58,7 +82,7 @@ public class BGImageHeadlineBodyButtonModel: ContainerModel, MoleculeModelProtoc
|
|||||||
button = try typeContainer.decodeIfPresent(ButtonModel.self, forKey: .button)
|
button = try typeContainer.decodeIfPresent(ButtonModel.self, forKey: .button)
|
||||||
try super.init(from: decoder)
|
try super.init(from: decoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func encode(to encoder: Encoder) throws {
|
public override func encode(to encoder: Encoder) throws {
|
||||||
try super.encode(to: encoder)
|
try super.encode(to: encoder)
|
||||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
@ -69,4 +93,3 @@ public class BGImageHeadlineBodyButtonModel: ContainerModel, MoleculeModelProtoc
|
|||||||
try container.encodeIfPresent(button, forKey: .button)
|
try container.encodeIfPresent(button, forKey: .button)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,6 @@
|
|||||||
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
@objcMembers open class EyebrowHeadlineBodyLink: View {
|
@objcMembers open class EyebrowHeadlineBodyLink: View {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -76,8 +75,9 @@ import UIKit
|
|||||||
|
|
||||||
/// Returns the labels text in one message.
|
/// Returns the labels text in one message.
|
||||||
func getAccessibilityMessage() -> String? {
|
func getAccessibilityMessage() -> String? {
|
||||||
|
|
||||||
var message = ""
|
var message = ""
|
||||||
|
|
||||||
if let eyebrowLabel = eyebrow.text {
|
if let eyebrowLabel = eyebrow.text {
|
||||||
message += eyebrowLabel + ", "
|
message += eyebrowLabel + ", "
|
||||||
}
|
}
|
||||||
@ -89,24 +89,31 @@ import UIKit
|
|||||||
if let bodyLabel = body.text {
|
if let bodyLabel = body.text {
|
||||||
message += bodyLabel
|
message += bodyLabel
|
||||||
}
|
}
|
||||||
|
|
||||||
return message.count > 0 ? message : nil
|
return message.count > 0 ? message : nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an array of the appropriate accessibility elements.
|
/// Returns an array of the appropriate accessibility elements.
|
||||||
func getAccessibilityElements() -> [Any]? {
|
func getAccessibilityElements() -> [Any]? {
|
||||||
|
|
||||||
var elements: [UIView] = []
|
var elements: [UIView] = []
|
||||||
|
|
||||||
if eyebrow.hasText {
|
if eyebrow.hasText {
|
||||||
elements.append(eyebrow)
|
elements.append(eyebrow)
|
||||||
}
|
}
|
||||||
|
|
||||||
if headline.hasText {
|
if headline.hasText {
|
||||||
elements.append(headline)
|
elements.append(headline)
|
||||||
}
|
}
|
||||||
|
|
||||||
if body.hasText {
|
if body.hasText {
|
||||||
elements.append(body)
|
elements.append(body)
|
||||||
}
|
}
|
||||||
|
|
||||||
if link.titleLabel?.text?.count ?? 0 > 0 {
|
if link.titleLabel?.text?.count ?? 0 > 0 {
|
||||||
elements.append(link)
|
elements.append(link)
|
||||||
}
|
}
|
||||||
|
|
||||||
return elements.count > 0 ? elements : nil
|
return elements.count > 0 ? elements : nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,6 @@
|
|||||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
public class EyebrowHeadlineBodyLinkModel: MoleculeModelProtocol {
|
public class EyebrowHeadlineBodyLinkModel: MoleculeModelProtocol {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -6,77 +6,88 @@
|
|||||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
@objcMembers public class HeadLineBodyCaretLinkImage: Container {
|
@objcMembers public class HeadLineBodyCaretLinkImage: Container {
|
||||||
let headlineBody = HeadlineBody(frame: .zero)
|
//--------------------------------------------------
|
||||||
let caretButton = CaretLink(frame: .zero)
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
let headlineBody = HeadlineBody()
|
||||||
|
let caretButton = CaretLink()
|
||||||
let backgroundImageView = LoadImageView(pinnedEdges: .all)
|
let backgroundImageView = LoadImageView(pinnedEdges: .all)
|
||||||
let maxWidth: CGFloat = 350.0
|
|
||||||
static let heightConstant: CGFloat = 320.0
|
//--------------------------------------------------
|
||||||
|
// MARK: - Constraints
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
let maxWidth: CGFloat = 350
|
||||||
|
static let heightConstant: CGFloat = 320
|
||||||
var heightConstraint: NSLayoutConstraint?
|
var heightConstraint: NSLayoutConstraint?
|
||||||
|
|
||||||
// MARK: - MVMCoreViewProtocol
|
//--------------------------------------------------
|
||||||
open override func updateView(_ size: CGFloat) {
|
// MARK: - Setup
|
||||||
super.updateView(size)
|
//--------------------------------------------------
|
||||||
headlineBody.updateView(size)
|
|
||||||
caretButton.updateView(size)
|
|
||||||
backgroundImageView.updateView(size)
|
|
||||||
backgroundImageView.pinEdges(.all)
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func setupView() {
|
open override func setupView() {
|
||||||
super.setupView()
|
super.setupView()
|
||||||
|
|
||||||
heightConstraint = heightAnchor.constraint(equalToConstant: Self.heightConstant)
|
heightConstraint = heightAnchor.constraint(equalToConstant: Self.heightConstant)
|
||||||
heightConstraint?.isActive = true
|
heightConstraint?.isActive = true
|
||||||
|
|
||||||
backgroundImageView.addSizeConstraintsForAspectRatio = true
|
backgroundImageView.addSizeConstraintsForAspectRatio = true
|
||||||
|
|
||||||
let container = MVMCoreUICommonViewsUtility.commonView()
|
let container = MVMCoreUICommonViewsUtility.commonView()
|
||||||
addAndContain(container)
|
addAndContain(container)
|
||||||
|
|
||||||
container.addSubview(headlineBody)
|
container.addSubview(headlineBody)
|
||||||
container.addSubview(caretButton)
|
container.addSubview(caretButton)
|
||||||
|
|
||||||
//Headline view
|
|
||||||
headlineBody.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 0).isActive = true
|
headlineBody.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 0).isActive = true
|
||||||
headlineBody.topAnchor.constraint(equalTo: container.topAnchor, constant: 0).isActive = true
|
headlineBody.topAnchor.constraint(equalTo: container.topAnchor, constant: 0).isActive = true
|
||||||
|
|
||||||
headlineBody.widthAnchor.constraint(equalTo: container.widthAnchor, multiplier: 0.67).isActive = true
|
headlineBody.widthAnchor.constraint(equalTo: container.widthAnchor, multiplier: 0.67).isActive = true
|
||||||
let headLineBodyWidth = headlineBody.widthAnchor.constraint(lessThanOrEqualToConstant: maxWidth)
|
let headLineBodyWidth = headlineBody.widthAnchor.constraint(lessThanOrEqualToConstant: maxWidth)
|
||||||
headLineBodyWidth.priority = UILayoutPriority(250)
|
headLineBodyWidth.priority = UILayoutPriority(250)
|
||||||
headLineBodyWidth.isActive = true
|
headLineBodyWidth.isActive = true
|
||||||
|
|
||||||
//Caret view
|
|
||||||
caretButton.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
caretButton.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 0).isActive = true
|
caretButton.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 0).isActive = true
|
||||||
container.bottomAnchor.constraint(equalTo: caretButton.bottomAnchor, constant: 0).isActive = true
|
container.bottomAnchor.constraint(equalTo: caretButton.bottomAnchor, constant: 0).isActive = true
|
||||||
|
|
||||||
caretButton.topAnchor.constraint(greaterThanOrEqualTo: headlineBody.bottomAnchor, constant: PaddingTwo).isActive = true
|
caretButton.topAnchor.constraint(greaterThanOrEqualTo: headlineBody.bottomAnchor, constant: PaddingTwo).isActive = true
|
||||||
|
|
||||||
//Background image view
|
|
||||||
backgroundImageView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
backgroundImageView.imageView.contentMode = .scaleAspectFill
|
backgroundImageView.imageView.contentMode = .scaleAspectFill
|
||||||
backgroundImageView.pinEdges(.all)
|
backgroundImageView.pinEdges(.all)
|
||||||
addSubview(backgroundImageView)
|
addSubview(backgroundImageView)
|
||||||
NSLayoutConstraint.constraintPinSubview(toSuperview: backgroundImageView)
|
NSLayoutConstraint.constraintPinSubview(toSuperview: backgroundImageView)
|
||||||
sendSubviewToBack(backgroundImageView)
|
sendSubviewToBack(backgroundImageView)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
// MARK: - MoleculeViewProtocol
|
// MARK: - MoleculeViewProtocol
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open override func updateView(_ size: CGFloat) {
|
||||||
|
super.updateView(size)
|
||||||
|
headlineBody.updateView(size)
|
||||||
|
caretButton.updateView(size)
|
||||||
|
backgroundImageView.updateView(size)
|
||||||
|
backgroundImageView.pinEdges(.all)
|
||||||
|
}
|
||||||
|
|
||||||
open override func reset() {
|
open override func reset() {
|
||||||
super.reset()
|
super.reset()
|
||||||
headlineBody.reset()
|
headlineBody.reset()
|
||||||
backgroundImageView.reset()
|
backgroundImageView.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK:- MoleculeViewProtocol
|
|
||||||
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||||
return 320
|
return 320
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
|
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
super.set(with: model, delegateObject, additionalData)
|
super.set(with: model, delegateObject, additionalData)
|
||||||
|
|
||||||
guard let model = model as? HeadlineBodyCaretLinkImageModel else { return }
|
guard let model = model as? HeadlineBodyCaretLinkImageModel else { return }
|
||||||
|
|
||||||
headlineBody.set(with: model.headlineBody, delegateObject, additionalData)
|
headlineBody.set(with: model.headlineBody, delegateObject, additionalData)
|
||||||
caretButton.setOptional(with: model.caretLink, delegateObject, additionalData)
|
caretButton.setOptional(with: model.caretLink, delegateObject, additionalData)
|
||||||
caretButton.isHidden = model.caretLink == nil
|
caretButton.isHidden = model.caretLink == nil
|
||||||
|
|||||||
@ -6,12 +6,19 @@
|
|||||||
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
open class HeadlineBody: View {
|
open class HeadlineBody: View {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Outlets
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
let headlineLabel = Label(fontStyle: .BoldTitleLarge)
|
let headlineLabel = Label(fontStyle: .BoldTitleLarge)
|
||||||
let messageLabel = Label(fontStyle: .RegularBodySmall)
|
let messageLabel = Label(fontStyle: .RegularBodySmall)
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Constraints
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
var spaceBetweenLabelsConstant = PaddingOne
|
var spaceBetweenLabelsConstant = PaddingOne
|
||||||
var spaceBetweenLabels: NSLayoutConstraint?
|
var spaceBetweenLabels: NSLayoutConstraint?
|
||||||
var leftConstraintTitle: NSLayoutConstraint?
|
var leftConstraintTitle: NSLayoutConstraint?
|
||||||
@ -19,21 +26,30 @@ open class HeadlineBody: View {
|
|||||||
var leftConstraintMessage: NSLayoutConstraint?
|
var leftConstraintMessage: NSLayoutConstraint?
|
||||||
var rightConstraintMessage: NSLayoutConstraint?
|
var rightConstraintMessage: NSLayoutConstraint?
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Methods
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
func hasText() -> Bool {
|
func hasText() -> Bool {
|
||||||
return headlineLabel.hasText || messageLabel.hasText
|
return headlineLabel.hasText || messageLabel.hasText
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Styling
|
// MARK: - Styling
|
||||||
func style(with style: HeadlineBodyModel.Style?) {
|
func style(with style: HeadlineBodyModel.Style?) {
|
||||||
|
|
||||||
switch style {
|
switch style {
|
||||||
case .landingHeader:
|
case .landingHeader:
|
||||||
styleLandingPageHeader()
|
styleLandingPageHeader()
|
||||||
|
|
||||||
case .header:
|
case .header:
|
||||||
stylePageHeader()
|
stylePageHeader()
|
||||||
|
|
||||||
case .item:
|
case .item:
|
||||||
styleListItem()
|
styleListItem()
|
||||||
|
|
||||||
case .itemHeader:
|
case .itemHeader:
|
||||||
styleListItemDivider()
|
styleListItemDivider()
|
||||||
|
|
||||||
default: break
|
default: break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,18 +77,14 @@ open class HeadlineBody: View {
|
|||||||
messageLabel.setFontStyle(.RegularBodySmall)
|
messageLabel.setFontStyle(.RegularBodySmall)
|
||||||
spaceBetweenLabelsConstant = 0
|
spaceBetweenLabelsConstant = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
// MARK: - MVMCoreViewProtocol
|
// MARK: - MVMCoreViewProtocol
|
||||||
open override func updateView(_ size: CGFloat) {
|
//--------------------------------------------------
|
||||||
super.updateView(size)
|
|
||||||
headlineLabel.updateView(size)
|
|
||||||
messageLabel.updateView(size)
|
|
||||||
setSpacing()
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func setupView() {
|
open override func setupView() {
|
||||||
super.setupView()
|
super.setupView()
|
||||||
|
|
||||||
backgroundColor = .clear
|
backgroundColor = .clear
|
||||||
clipsToBounds = true
|
clipsToBounds = true
|
||||||
|
|
||||||
@ -86,35 +98,42 @@ open class HeadlineBody: View {
|
|||||||
|
|
||||||
view.addSubview(headlineLabel)
|
view.addSubview(headlineLabel)
|
||||||
view.addSubview(messageLabel)
|
view.addSubview(messageLabel)
|
||||||
|
|
||||||
headlineLabel.setContentHuggingPriority(.required, for: .vertical)
|
headlineLabel.setContentHuggingPriority(.required, for: .vertical)
|
||||||
messageLabel.setContentHuggingPriority(.required, for: .vertical)
|
messageLabel.setContentHuggingPriority(.required, for: .vertical)
|
||||||
view.setContentHuggingPriority(.required, for: .vertical)
|
view.setContentHuggingPriority(.required, for: .vertical)
|
||||||
|
|
||||||
headlineLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
|
headlineLabel.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
|
||||||
|
|
||||||
spaceBetweenLabels = messageLabel.topAnchor.constraint(equalTo: headlineLabel.bottomAnchor, constant: spaceBetweenLabelsConstant)
|
spaceBetweenLabels = messageLabel.topAnchor.constraint(equalTo: headlineLabel.bottomAnchor, constant: spaceBetweenLabelsConstant)
|
||||||
spaceBetweenLabels?.isActive = true
|
spaceBetweenLabels?.isActive = true
|
||||||
|
|
||||||
leftConstraintTitle = headlineLabel.leftAnchor.constraint(equalTo: view.leftAnchor)
|
leftConstraintTitle = headlineLabel.leftAnchor.constraint(equalTo: view.leftAnchor)
|
||||||
leftConstraintTitle?.isActive = true
|
leftConstraintTitle?.isActive = true
|
||||||
|
|
||||||
rightConstraintTitle = view.rightAnchor.constraint(equalTo: headlineLabel.rightAnchor)
|
rightConstraintTitle = view.rightAnchor.constraint(equalTo: headlineLabel.rightAnchor)
|
||||||
rightConstraintTitle?.isActive = true
|
rightConstraintTitle?.isActive = true
|
||||||
|
|
||||||
leftConstraintMessage = messageLabel.leftAnchor.constraint(equalTo: view.leftAnchor)
|
leftConstraintMessage = messageLabel.leftAnchor.constraint(equalTo: view.leftAnchor)
|
||||||
leftConstraintMessage?.isActive = true
|
leftConstraintMessage?.isActive = true
|
||||||
|
|
||||||
rightConstraintMessage = view.rightAnchor.constraint(equalTo: messageLabel.rightAnchor)
|
rightConstraintMessage = view.rightAnchor.constraint(equalTo: messageLabel.rightAnchor)
|
||||||
rightConstraintMessage?.isActive = true
|
rightConstraintMessage?.isActive = true
|
||||||
|
|
||||||
view.bottomAnchor.constraint(equalTo: messageLabel.bottomAnchor, constant: 0).isActive = true
|
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
|
// MARK: - Constraining
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
public func setSpacing() {
|
public func setSpacing() {
|
||||||
if headlineLabel.hasText && messageLabel.hasText {
|
if headlineLabel.hasText && messageLabel.hasText {
|
||||||
spaceBetweenLabels?.constant = spaceBetweenLabelsConstant
|
spaceBetweenLabels?.constant = spaceBetweenLabelsConstant
|
||||||
@ -122,7 +141,7 @@ open class HeadlineBody: View {
|
|||||||
spaceBetweenLabels?.constant = 0
|
spaceBetweenLabels?.constant = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - MoleculeViewProtocol
|
// MARK: - MoleculeViewProtocol
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -135,7 +154,7 @@ open class HeadlineBody: View {
|
|||||||
super.set(with: model, delegateObject, additionalData)
|
super.set(with: model, delegateObject, additionalData)
|
||||||
|
|
||||||
guard let headlineBodyModel = model as? HeadlineBodyModel else { return }
|
guard let headlineBodyModel = model as? HeadlineBodyModel else { return }
|
||||||
|
|
||||||
style(with: headlineBodyModel.style)
|
style(with: headlineBodyModel.style)
|
||||||
|
|
||||||
headlineLabel.setOptional(with: headlineBodyModel.headline, delegateObject, additionalData)
|
headlineLabel.setOptional(with: headlineBodyModel.headline, delegateObject, additionalData)
|
||||||
|
|||||||
@ -6,8 +6,6 @@
|
|||||||
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
|
|
||||||
@objcMembers open class HeadlineBodyButton: View {
|
@objcMembers open class HeadlineBodyButton: View {
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
|
|||||||
@ -6,8 +6,6 @@
|
|||||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
|
|
||||||
public class HeadlineBodyButtonModel: MoleculeModelProtocol {
|
public class HeadlineBodyButtonModel: MoleculeModelProtocol {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -17,7 +15,7 @@ public class HeadlineBodyButtonModel: MoleculeModelProtocol {
|
|||||||
public static var identifier: String = "headlineBodyButton"
|
public static var identifier: String = "headlineBodyButton"
|
||||||
public var moleculeName: String = HeadlineBodyButtonModel.identifier
|
public var moleculeName: String = HeadlineBodyButtonModel.identifier
|
||||||
public var backgroundColor: Color?
|
public var backgroundColor: Color?
|
||||||
|
|
||||||
public var headlineBody: HeadlineBodyModel
|
public var headlineBody: HeadlineBodyModel
|
||||||
public var button: ButtonModel
|
public var button: ButtonModel
|
||||||
public var buttonHeadlinePadding: CGFloat
|
public var buttonHeadlinePadding: CGFloat
|
||||||
|
|||||||
@ -6,40 +6,60 @@
|
|||||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
public class HeadlineBodyCaretLinkImageModel: ContainerModel, MoleculeModelProtocol {
|
public class HeadlineBodyCaretLinkImageModel: ContainerModel, MoleculeModelProtocol {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public static var identifier: String = "headlineBodyCaretLinkImage"
|
public static var identifier: String = "headlineBodyCaretLinkImage"
|
||||||
public var backgroundColor: Color?
|
public var backgroundColor: Color?
|
||||||
public var caretLink: CaretLinkModel?
|
public var caretLink: CaretLinkModel?
|
||||||
public var headlineBody: HeadlineBodyModel
|
public var headlineBody: HeadlineBodyModel
|
||||||
public var image: ImageViewModel
|
public var image: ImageViewModel
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Initializer
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
init(headlineBody: HeadlineBodyModel, image: ImageViewModel) {
|
init(headlineBody: HeadlineBodyModel, image: ImageViewModel) {
|
||||||
self.headlineBody = headlineBody
|
self.headlineBody = headlineBody
|
||||||
self.image = image
|
self.image = image
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Defaults
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
/// Defaults to set
|
/// Defaults to set
|
||||||
public override func setDefaults() {
|
public override func setDefaults() {
|
||||||
|
|
||||||
if useHorizontalMargins == nil {
|
if useHorizontalMargins == nil {
|
||||||
useHorizontalMargins = true
|
useHorizontalMargins = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if useVerticalMargins == nil {
|
if useVerticalMargins == nil {
|
||||||
useVerticalMargins = true
|
useVerticalMargins = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if topPadding == nil {
|
if topPadding == nil {
|
||||||
topPadding = PaddingDefault
|
topPadding = PaddingDefault
|
||||||
}
|
}
|
||||||
|
|
||||||
if bottomPadding == nil {
|
if bottomPadding == nil {
|
||||||
bottomPadding = PaddingDefault
|
bottomPadding = PaddingDefault
|
||||||
}
|
}
|
||||||
|
|
||||||
if image.height == nil {
|
if image.height == nil {
|
||||||
image.height = HeadLineBodyCaretLinkImage.heightConstant
|
image.height = HeadLineBodyCaretLinkImage.heightConstant
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Keys
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case moleculeName
|
case moleculeName
|
||||||
case backgroundColor
|
case backgroundColor
|
||||||
@ -47,7 +67,11 @@ public class HeadlineBodyCaretLinkImageModel: ContainerModel, MoleculeModelProto
|
|||||||
case image
|
case image
|
||||||
case caretLink
|
case caretLink
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Codec
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||||
@ -56,7 +80,7 @@ public class HeadlineBodyCaretLinkImageModel: ContainerModel, MoleculeModelProto
|
|||||||
caretLink = try typeContainer.decodeIfPresent(CaretLinkModel.self, forKey: .caretLink)
|
caretLink = try typeContainer.decodeIfPresent(CaretLinkModel.self, forKey: .caretLink)
|
||||||
try super.init(from: decoder)
|
try super.init(from: decoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func encode(to encoder: Encoder) throws {
|
public override func encode(to encoder: Encoder) throws {
|
||||||
try super.encode(to: encoder)
|
try super.encode(to: encoder)
|
||||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|||||||
@ -6,33 +6,41 @@
|
|||||||
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
@objcMembers public class HeadlineBodyLink: View {
|
@objcMembers public class HeadlineBodyLink: View {
|
||||||
|
//--------------------------------------------------
|
||||||
let headlineBody = HeadlineBody(frame: .zero)
|
// MARK: - Outlets
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
let headlineBody = HeadlineBody()
|
||||||
let link = Link()
|
let link = Link()
|
||||||
var spaceBetweenConstant: CGFloat = 0.0
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
var spaceBetweenConstant: CGFloat = 0
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Constraints
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
var spaceBetween: NSLayoutConstraint?
|
var spaceBetween: NSLayoutConstraint?
|
||||||
|
|
||||||
// MARK: - MVMCoreViewProtocol
|
//--------------------------------------------------
|
||||||
open override func updateView(_ size: CGFloat) {
|
// MARK: - Setup
|
||||||
super.updateView(size)
|
//--------------------------------------------------
|
||||||
headlineBody.updateView(size)
|
|
||||||
link.updateView(size)
|
|
||||||
setSpacing()
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func setupView() {
|
open override func setupView() {
|
||||||
super.setupView()
|
super.setupView()
|
||||||
guard subviews.count == 0 else {
|
|
||||||
return
|
guard subviews.isEmpty else { return }
|
||||||
}
|
|
||||||
addSubview(headlineBody)
|
addSubview(headlineBody)
|
||||||
addSubview(link)
|
addSubview(link)
|
||||||
headlineBody.styleListItem()
|
headlineBody.styleListItem()
|
||||||
|
|
||||||
headlineBody.topAnchor.constraint(equalTo: topAnchor, constant: 0).isActive = true
|
headlineBody.topAnchor.constraint(equalTo: topAnchor).isActive = true
|
||||||
headlineBody.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
|
headlineBody.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
|
||||||
rightAnchor.constraint(greaterThanOrEqualTo: headlineBody.rightAnchor).isActive = true
|
rightAnchor.constraint(greaterThanOrEqualTo: headlineBody.rightAnchor).isActive = true
|
||||||
var constraint = rightAnchor.constraint(equalTo: headlineBody.rightAnchor)
|
var constraint = rightAnchor.constraint(equalTo: headlineBody.rightAnchor)
|
||||||
@ -50,7 +58,10 @@ import UIKit
|
|||||||
constraint.isActive = true
|
constraint.isActive = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Constraining
|
//--------------------------------------------------
|
||||||
|
// MARK: - Methods
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public func setSpacing() {
|
public func setSpacing() {
|
||||||
if headlineBody.hasText() && (link.titleLabel?.text?.count ?? 0) > 0 {
|
if headlineBody.hasText() && (link.titleLabel?.text?.count ?? 0) > 0 {
|
||||||
spaceBetween?.constant = spaceBetweenConstant
|
spaceBetween?.constant = spaceBetweenConstant
|
||||||
@ -59,7 +70,17 @@ import UIKit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - MoleculeViewProtocol
|
//--------------------------------------------------
|
||||||
|
// MARK: - MVMCoreViewProtocol
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open override func updateView(_ size: CGFloat) {
|
||||||
|
super.updateView(size)
|
||||||
|
headlineBody.updateView(size)
|
||||||
|
link.updateView(size)
|
||||||
|
setSpacing()
|
||||||
|
}
|
||||||
|
|
||||||
open override func reset() {
|
open override func reset() {
|
||||||
super.reset()
|
super.reset()
|
||||||
headlineBody.reset()
|
headlineBody.reset()
|
||||||
@ -67,7 +88,6 @@ import UIKit
|
|||||||
link.reset()
|
link.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK:- MoleculeViewProtocol
|
|
||||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
super.set(with: model, delegateObject, additionalData)
|
super.set(with: model, delegateObject, additionalData)
|
||||||
guard let model = model as? HeadlineBodyLinkModel else { return }
|
guard let model = model as? HeadlineBodyLinkModel else { return }
|
||||||
|
|||||||
@ -8,13 +8,22 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
public struct HeadlineBodyLinkModel: MoleculeModelProtocol {
|
public struct HeadlineBodyLinkModel: MoleculeModelProtocol {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public static var identifier: String = "headlineBodyLink"
|
public static var identifier: String = "headlineBodyLink"
|
||||||
public var moleculeName: String = HeadlineBodyLinkModel.identifier
|
public var moleculeName: String = HeadlineBodyLinkModel.identifier
|
||||||
public var headlineBody: HeadlineBodyModel
|
public var headlineBody: HeadlineBodyModel
|
||||||
public var link: LinkModel
|
public var link: LinkModel
|
||||||
public var backgroundColor: Color?
|
public var backgroundColor: Color?
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Initializer
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public init(headlineBody: HeadlineBodyModel, link: LinkModel) {
|
public init(headlineBody: HeadlineBodyModel, link: LinkModel) {
|
||||||
self.headlineBody = headlineBody
|
self.headlineBody = headlineBody
|
||||||
self.link = link
|
self.link = link
|
||||||
|
|||||||
@ -8,11 +8,15 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
|
||||||
// This class is only temporarily necessary. Eventually we will have initWithModel instad of just init for moleculeviews, which will remove this need.
|
// This class is only temporarily necessary. Eventually we will have initWithModel instad of just init for moleculeviews, which will remove this need.
|
||||||
open class StringAndMoleculeStack: MoleculeStackView {
|
open class StringAndMoleculeStack: MoleculeStackView {
|
||||||
override open func createStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
override open func createStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
|
|
||||||
guard let model = model as? StackModelProtocol,
|
guard let model = model as? StackModelProtocol,
|
||||||
let molcules = model.molecules as? [MoleculeStackItemModel] else { return }
|
let molcules = model.molecules as? [MoleculeStackItemModel]
|
||||||
|
else { return }
|
||||||
|
|
||||||
for stackItemModel in molcules {
|
for stackItemModel in molcules {
|
||||||
guard let stringAndMoleculeModel = stackItemModel.molecule as? StringAndMoleculeModel,
|
guard let stringAndMoleculeModel = stackItemModel.molecule as? StringAndMoleculeModel,
|
||||||
let molecule = MoleculeObjectMapping.shared()?.createMolecule(stringAndMoleculeModel.molecule, delegateObject: delegateObject
|
let molecule = MoleculeObjectMapping.shared()?.createMolecule(stringAndMoleculeModel.molecule, delegateObject: delegateObject
|
||||||
|
|||||||
@ -6,9 +6,9 @@
|
|||||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
open class StringAndMoleculeView: View {
|
open class StringAndMoleculeView: View {
|
||||||
|
|
||||||
var label = Label(fontStyle: .RegularBodySmall)
|
var label = Label(fontStyle: .RegularBodySmall)
|
||||||
var molecule: MoleculeViewProtocol
|
var molecule: MoleculeViewProtocol
|
||||||
|
|
||||||
@ -45,11 +45,9 @@ open class StringAndMoleculeView: View {
|
|||||||
|
|
||||||
override public func setupView() {
|
override public func setupView() {
|
||||||
super.setupView()
|
super.setupView()
|
||||||
guard subviews.count == 0 else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
translatesAutoresizingMaskIntoConstraints = false
|
guard subviews.count == 0 else { return }
|
||||||
|
|
||||||
addSubview(label)
|
addSubview(label)
|
||||||
addSubview(molecule)
|
addSubview(molecule)
|
||||||
|
|
||||||
@ -82,7 +80,7 @@ open class StringAndMoleculeView: View {
|
|||||||
molecule.reset()
|
molecule.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
|
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
super.set(with: model, delegateObject, additionalData)
|
super.set(with: model, delegateObject, additionalData)
|
||||||
guard let model = model as? StringAndMoleculeModel else { return }
|
guard let model = model as? StringAndMoleculeModel else { return }
|
||||||
label.text = model.string
|
label.text = model.string
|
||||||
@ -92,7 +90,7 @@ open class StringAndMoleculeView: View {
|
|||||||
func updateLeftViewWidthConstraint(_ percent: CGFloat) {
|
func updateLeftViewWidthConstraint(_ percent: CGFloat) {
|
||||||
percentage = percent
|
percentage = percent
|
||||||
leftWidthConstraint?.isActive = false
|
leftWidthConstraint?.isActive = false
|
||||||
leftWidthConstraint = label.widthAnchor.constraint(equalTo: widthAnchor, multiplier: CGFloat(percent/100), constant: 0)
|
leftWidthConstraint = label.widthAnchor.constraint(equalTo: widthAnchor, multiplier: CGFloat(percent / 100), constant: 0)
|
||||||
leftWidthConstraint?.isActive = true
|
leftWidthConstraint?.isActive = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,8 +6,6 @@
|
|||||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
|
|
||||||
open class ThreeHeadlineBodyLink: View {
|
open class ThreeHeadlineBodyLink: View {
|
||||||
//-------------------------------------------------------
|
//-------------------------------------------------------
|
||||||
|
|||||||
@ -9,12 +9,16 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
|
||||||
open class MoleculeStackView: Stack<StackModel> {
|
open class MoleculeStackView: Stack<StackModel> {
|
||||||
|
|
||||||
var previousModel: MoleculeModelProtocol?
|
var previousModel: MoleculeModelProtocol?
|
||||||
|
|
||||||
/// Convenience function, adds a molecule to a MoleculeStackItem to the MoleculeStack
|
/// Convenience function, adds a molecule to a MoleculeStackItem to the MoleculeStack
|
||||||
func setup(with views: [View], lastItem: Bool) {
|
func setup(with views: [View], lastItem: Bool) {
|
||||||
|
|
||||||
var models: [MoleculeStackItemModel] = []
|
var models: [MoleculeStackItemModel] = []
|
||||||
|
|
||||||
for view in views {
|
for view in views {
|
||||||
guard let model = view.model else { return }
|
guard let model = view.model else { return }
|
||||||
let stackItemModel = MoleculeStackItemModel(with: model)
|
let stackItemModel = MoleculeStackItemModel(with: model)
|
||||||
@ -22,20 +26,22 @@ open class MoleculeStackView: Stack<StackModel> {
|
|||||||
stackItems.append(stackItem)
|
stackItems.append(stackItem)
|
||||||
models.append(stackItemModel)
|
models.append(stackItemModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let stackModel = stackModel {
|
if let stackModel = stackModel {
|
||||||
stackModel.molecules = models
|
stackModel.molecules = models
|
||||||
} else {
|
} else {
|
||||||
model = StackModel(molecules: models)
|
model = StackModel(molecules: models)
|
||||||
}
|
}
|
||||||
|
|
||||||
restack()
|
restack()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Adding to stack
|
// MARK: - Adding to stack
|
||||||
/// Can be subclassed to create views when we get stack item models and have no views yet
|
/// Can be subclassed to create views when we get stack item models and have no views yet
|
||||||
open func createStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
|
open func createStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
|
|
||||||
guard let stackItemModels = stackModel?.molecules else { return }
|
guard let stackItemModels = stackModel?.molecules else { return }
|
||||||
|
|
||||||
for model in stackItemModels {
|
for model in stackItemModels {
|
||||||
if let stackItem = MoleculeObjectMapping.shared()?.createMolecule(model, delegateObject: delegateObject, additionalData: additionalData) as? MoleculeStackItem {
|
if let stackItem = MoleculeObjectMapping.shared()?.createMolecule(model, delegateObject: delegateObject, additionalData: additionalData) as? MoleculeStackItem {
|
||||||
stackItems.append(stackItem)
|
stackItems.append(stackItem)
|
||||||
@ -43,8 +49,8 @@ open class MoleculeStackView: Stack<StackModel> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func setStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
|
open override func setStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
// If the items in the stack are different, clear them, create new ones.
|
// If the items in the stack are different, clear them, create new ones.
|
||||||
if (previousModel == nil) || Self.nameForReuse(with: previousModel!, delegateObject) != Self.nameForReuse(with: model, delegateObject) {
|
if (previousModel == nil) || Self.nameForReuse(with: previousModel!, delegateObject) != Self.nameForReuse(with: model, delegateObject) {
|
||||||
removeAllItemViews()
|
removeAllItemViews()
|
||||||
stackItems = []
|
stackItems = []
|
||||||
|
|||||||
@ -6,8 +6,6 @@
|
|||||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
|
|
||||||
open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProtocol) {
|
open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProtocol) {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -24,7 +22,7 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Helpers
|
// MARK: - Helpers
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
open func pinView(_ view: UIView, toView: UIView, attribute: NSLayoutConstraint.Attribute, relation: NSLayoutConstraint.Relation, priority: UILayoutPriority, constant: CGFloat) {
|
open func pinView(_ view: UIView, toView: UIView, attribute: NSLayoutConstraint.Attribute, relation: NSLayoutConstraint.Relation, priority: UILayoutPriority, constant: CGFloat) {
|
||||||
|
|
||||||
let constraint = NSLayoutConstraint(item: view, attribute: attribute, relatedBy: relation, toItem: toView, attribute: attribute, multiplier: 1.0, constant: constant)
|
let constraint = NSLayoutConstraint(item: view, attribute: attribute, relatedBy: relation, toItem: toView, attribute: attribute, multiplier: 1.0, constant: constant)
|
||||||
@ -34,8 +32,11 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
|
|||||||
|
|
||||||
/// Restacks the existing items.
|
/// Restacks the existing items.
|
||||||
open func restack() {
|
open func restack() {
|
||||||
|
|
||||||
removeAllItemViews()
|
removeAllItemViews()
|
||||||
|
|
||||||
guard let stackModel = stackModel else { return }
|
guard let stackModel = stackModel else { return }
|
||||||
|
|
||||||
let stackItems = self.stackItems
|
let stackItems = self.stackItems
|
||||||
self.stackItems = []
|
self.stackItems = []
|
||||||
let lastItemIndex = stackModel.molecules.lastIndex { !$0.gone }
|
let lastItemIndex = stackModel.molecules.lastIndex { !$0.gone }
|
||||||
@ -48,6 +49,7 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
|
|||||||
|
|
||||||
isAccessibilityElement = false
|
isAccessibilityElement = false
|
||||||
var accessibleViews: [Any] = []
|
var accessibleViews: [Any] = []
|
||||||
|
|
||||||
for (index, view) in stackItems.enumerated() where !stackModel.molecules[index].gone {
|
for (index, view) in stackItems.enumerated() where !stackModel.molecules[index].gone {
|
||||||
accessibleViews.append(view)
|
accessibleViews.append(view)
|
||||||
}
|
}
|
||||||
@ -57,20 +59,20 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
|
|||||||
|
|
||||||
/// Removes all stack items views from the view.
|
/// Removes all stack items views from the view.
|
||||||
open func removeAllItemViews() {
|
open func removeAllItemViews() {
|
||||||
for item in stackItems {
|
stackItems.forEach { $0.removeFromSuperview() }
|
||||||
item.removeFromSuperview()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A convenience function for when the stackItems are containers and we want to update them based on the contained molecules models. If model is nil, stackItem is set to gone. Restacks if necessary.
|
/// A convenience function for when the stackItems are containers and we want to update them based on the contained molecules models. If model is nil, stackItem is set to gone. Restacks if necessary.
|
||||||
open func updateContainedMolecules(with models: [MoleculeModelProtocol?], _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
open func updateContainedMolecules(with models: [MoleculeModelProtocol?], _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
|
|
||||||
guard var stackModel = stackModel else { return }
|
guard var stackModel = stackModel else { return }
|
||||||
var needsRestack = false
|
var needsRestack = false
|
||||||
|
|
||||||
for (index, item) in stackItems.enumerated() {
|
for (index, item) in stackItems.enumerated() {
|
||||||
guard let container = item as? UIView & ContainerProtocol,
|
guard let container = item as? UIView & ContainerProtocol,
|
||||||
let contained = container.view as? MoleculeViewProtocol else {
|
let contained = container.view as? MoleculeViewProtocol
|
||||||
continue
|
else { continue }
|
||||||
}
|
|
||||||
if let model = models[index] {
|
if let model = models[index] {
|
||||||
contained.set(with: model, delegateObject, additionalData)
|
contained.set(with: model, delegateObject, additionalData)
|
||||||
if stackModel.molecules[index].gone {
|
if stackModel.molecules[index].gone {
|
||||||
@ -91,7 +93,7 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Initializers
|
// MARK: - Initializers
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
public override init(frame: CGRect) {
|
public override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
}
|
}
|
||||||
@ -120,12 +122,15 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
|
|||||||
|
|
||||||
/// Returns a Stack created with a StackModel and StackItems containing the passed in views.
|
/// Returns a Stack created with a StackModel and StackItems containing the passed in views.
|
||||||
public static func createStack(with views: [UIView], axis: NSLayoutConstraint.Axis? = nil, spacing: CGFloat? = nil) -> Stack<StackModel> {
|
public static func createStack(with views: [UIView], axis: NSLayoutConstraint.Axis? = nil, spacing: CGFloat? = nil) -> Stack<StackModel> {
|
||||||
|
|
||||||
var items: [StackItem] = []
|
var items: [StackItem] = []
|
||||||
var models: [StackItemModel] = []
|
var models: [StackItemModel] = []
|
||||||
|
|
||||||
for view in views {
|
for view in views {
|
||||||
items.append(StackItem(andContain: view))
|
items.append(StackItem(andContain: view))
|
||||||
models.append(StackItemModel())
|
models.append(StackItemModel())
|
||||||
}
|
}
|
||||||
|
|
||||||
let model = StackModel(molecules: models, axis: axis, spacing: spacing)
|
let model = StackModel(molecules: models, axis: axis, spacing: spacing)
|
||||||
return Stack<StackModel>(with: model, stackItems: items)
|
return Stack<StackModel>(with: model, stackItems: items)
|
||||||
}
|
}
|
||||||
@ -134,10 +139,12 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
|
|||||||
public static func createStack(with viewModels:[(view: UIView, model: StackItemModel)], axis: NSLayoutConstraint.Axis? = nil, spacing: CGFloat? = nil) -> Stack<StackModel> {
|
public static func createStack(with viewModels:[(view: UIView, model: StackItemModel)], axis: NSLayoutConstraint.Axis? = nil, spacing: CGFloat? = nil) -> Stack<StackModel> {
|
||||||
var stackItems: [StackItem] = []
|
var stackItems: [StackItem] = []
|
||||||
var models: [StackItemModel] = []
|
var models: [StackItemModel] = []
|
||||||
|
|
||||||
for item in viewModels {
|
for item in viewModels {
|
||||||
stackItems.append(StackItem(andContain: item.view))
|
stackItems.append(StackItem(andContain: item.view))
|
||||||
models.append(item.model)
|
models.append(item.model)
|
||||||
}
|
}
|
||||||
|
|
||||||
let model = StackModel(molecules: models, axis: axis, spacing: spacing)
|
let model = StackModel(molecules: models, axis: axis, spacing: spacing)
|
||||||
return Stack<StackModel>(with: model, stackItems: stackItems)
|
return Stack<StackModel>(with: model, stackItems: stackItems)
|
||||||
}
|
}
|
||||||
@ -145,10 +152,12 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - MFViewProtocol
|
// MARK: - MFViewProtocol
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
open override func setupView() {
|
open override func setupView() {
|
||||||
super.setupView()
|
super.setupView()
|
||||||
|
|
||||||
guard contentView.superview == nil else { return }
|
guard contentView.superview == nil else { return }
|
||||||
|
|
||||||
MVMCoreUIUtility.setMarginsFor(contentView, leading: 0, top: 0, trailing: 0, bottom: 0)
|
MVMCoreUIUtility.setMarginsFor(contentView, leading: 0, top: 0, trailing: 0, bottom: 0)
|
||||||
translatesAutoresizingMaskIntoConstraints = false
|
translatesAutoresizingMaskIntoConstraints = false
|
||||||
backgroundColor = .clear
|
backgroundColor = .clear
|
||||||
@ -168,7 +177,7 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - MoleculeViewProtocol
|
// MARK: - MoleculeViewProtocol
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
open override func reset() {
|
open override func reset() {
|
||||||
super.reset()
|
super.reset()
|
||||||
backgroundColor = .clear
|
backgroundColor = .clear
|
||||||
@ -223,13 +232,16 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
|
|||||||
}
|
}
|
||||||
|
|
||||||
open override class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
|
open override class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
|
||||||
|
|
||||||
guard let model = model as? T else { return nil }
|
guard let model = model as? T else { return nil }
|
||||||
var modules: [String] = []
|
var modules: [String] = []
|
||||||
|
|
||||||
for case let item in model.molecules {
|
for case let item in model.molecules {
|
||||||
if let modulesForMolecule = (MoleculeObjectMapping.shared()?.getMoleculeClass(item))?.requiredModules(with: item, delegateObject, error: error) {
|
if let modulesForMolecule = (MoleculeObjectMapping.shared()?.getMoleculeClass(item))?.requiredModules(with: item, delegateObject, error: error) {
|
||||||
modules += modulesForMolecule
|
modules += modulesForMolecule
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return modules.count > 0 ? modules : nil
|
return modules.count > 0 ? modules : nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,7 +251,9 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
|
|||||||
|
|
||||||
/// Can be subclassed to set stack items with model when we already have views
|
/// Can be subclassed to set stack items with model when we already have views
|
||||||
open func setStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
open func setStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
|
|
||||||
guard let models = stackModel?.molecules else { return }
|
guard let models = stackModel?.molecules else { return }
|
||||||
|
|
||||||
for (index, element) in models.enumerated() {
|
for (index, element) in models.enumerated() {
|
||||||
(stackItems[index] as? MoleculeViewProtocol)?.set(with: element, delegateObject, additionalData)
|
(stackItems[index] as? MoleculeViewProtocol)?.set(with: element, delegateObject, additionalData)
|
||||||
}
|
}
|
||||||
@ -250,31 +264,39 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
/// Sets the stack with StackItems containing the passed in views and creates a StackModel with StackItems.
|
/// Sets the stack with StackItems containing the passed in views and creates a StackModel with StackItems.
|
||||||
open func setAndCreateModel(with views: [UIView]) {
|
open func setAndCreateModel(with views: [UIView]) {
|
||||||
|
|
||||||
var stackItems: [StackItem] = []
|
var stackItems: [StackItem] = []
|
||||||
var models: [StackItemModel] = []
|
var models: [StackItemModel] = []
|
||||||
|
|
||||||
for view in views {
|
for view in views {
|
||||||
stackItems.append(StackItem(andContain: view))
|
stackItems.append(StackItem(andContain: view))
|
||||||
models.append(StackItemModel())
|
models.append(StackItemModel())
|
||||||
}
|
}
|
||||||
|
|
||||||
self.stackItems = stackItems
|
self.stackItems = stackItems
|
||||||
model = StackModel(molecules: models)
|
model = StackModel(molecules: models)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the stack with StackItems containing the passed in views and sets the StackModel with models.
|
/// Sets the stack with StackItems containing the passed in views and sets the StackModel with models.
|
||||||
open func set(with viewModels:[(view: UIView, model: StackItemModel)]) {
|
open func set(with viewModels:[(view: UIView, model: StackItemModel)]) {
|
||||||
|
|
||||||
guard var stackModel = self.stackModel else { return }
|
guard var stackModel = self.stackModel else { return }
|
||||||
|
|
||||||
var stackItems: [StackItem] = []
|
var stackItems: [StackItem] = []
|
||||||
var models: [StackItemModel] = []
|
var models: [StackItemModel] = []
|
||||||
|
|
||||||
for item in viewModels {
|
for item in viewModels {
|
||||||
stackItems.append(StackItem(andContain: item.view))
|
stackItems.append(StackItem(andContain: item.view))
|
||||||
models.append(item.model)
|
models.append(item.model)
|
||||||
}
|
}
|
||||||
|
|
||||||
stackModel.molecules = models
|
stackModel.molecules = models
|
||||||
self.stackItems = stackItems
|
self.stackItems = stackItems
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the percent modifier. This value is used to help properly calculate percent for stack items when spacing is involved.
|
/// Gets the percent modifier. This value is used to help properly calculate percent for stack items when spacing is involved.
|
||||||
private func getTotalSpace() -> CGFloat {
|
private func getTotalSpace() -> CGFloat {
|
||||||
|
|
||||||
guard let stackModel = stackModel else { return 0.0 }
|
guard let stackModel = stackModel else { return 0.0 }
|
||||||
var totalSpace: CGFloat = 0.0
|
var totalSpace: CGFloat = 0.0
|
||||||
var firstMoleculeFound = false
|
var firstMoleculeFound = false
|
||||||
@ -289,11 +311,13 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
|
|||||||
totalSpace += (stackModel.useStackSpacingBeforeFirstItem ? spacing : stackItemModel.spacing ?? 0)
|
totalSpace += (stackModel.useStackSpacingBeforeFirstItem ? spacing : stackItemModel.spacing ?? 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalSpace
|
return totalSpace
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds the stack item view
|
/// Adds the stack item view
|
||||||
private func addView(_ view: UIView,_ model: StackItemModelProtocol, totalSpacing: CGFloat, lastItem: Bool) {
|
private func addView(_ view: UIView,_ model: StackItemModelProtocol, totalSpacing: CGFloat, lastItem: Bool) {
|
||||||
|
|
||||||
guard let stackModel = self.stackModel else { return }
|
guard let stackModel = self.stackModel else { return }
|
||||||
guard !model.gone else {
|
guard !model.gone else {
|
||||||
// Gone views do not show
|
// Gone views do not show
|
||||||
@ -302,15 +326,15 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
|
|||||||
}
|
}
|
||||||
contentView.addSubview(view)
|
contentView.addSubview(view)
|
||||||
view.translatesAutoresizingMaskIntoConstraints = false
|
view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
|
||||||
let spacing = model.spacing ?? stackModel.spacing
|
let spacing = model.spacing ?? stackModel.spacing
|
||||||
if let container = view as? ContainerProtocol {
|
if let container = view as? ContainerProtocol {
|
||||||
let verticalAlignment = (model as? ContainerModelProtocol)?.verticalAlignment ?? (container.view as? MVMCoreUIViewConstrainingProtocol)?.verticalAlignment?() ?? (model.percent == nil && stackModel.axis == .vertical ? .fill : (stackModel.axis == .vertical ? .leading : .center))
|
let verticalAlignment = (model as? ContainerModelProtocol)?.verticalAlignment ?? (container.view as? MVMCoreUIViewConstrainingProtocol)?.verticalAlignment?() ?? (model.percent == nil && stackModel.axis == .vertical ? .fill : (stackModel.axis == .vertical ? .leading : .center))
|
||||||
let horizontalAlignment = (model as? ContainerModelProtocol)?.horizontalAlignment ?? (container.view as? MVMCoreUIViewConstrainingProtocol)?.horizontalAlignment?() ?? (stackModel.axis == .vertical || model.percent == nil ? .fill : .leading)
|
let horizontalAlignment = (model as? ContainerModelProtocol)?.horizontalAlignment ?? (container.view as? MVMCoreUIViewConstrainingProtocol)?.horizontalAlignment?() ?? (stackModel.axis == .vertical || model.percent == nil ? .fill : .leading)
|
||||||
container.alignHorizontal(horizontalAlignment)
|
container.alignHorizontal(horizontalAlignment)
|
||||||
container.alignVertical(verticalAlignment)
|
container.alignVertical(verticalAlignment)
|
||||||
}
|
}
|
||||||
|
|
||||||
let first = contentView.subviews.count == 1
|
let first = contentView.subviews.count == 1
|
||||||
if stackModel.axis == .vertical {
|
if stackModel.axis == .vertical {
|
||||||
if first {
|
if first {
|
||||||
@ -350,6 +374,7 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
|
|||||||
pinView(contentView, toView: view, attribute: .right, relation: .equal, priority: .required, constant: 0)
|
pinView(contentView, toView: view, attribute: .right, relation: .equal, priority: .required, constant: 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stackItems.append(view)
|
stackItems.append(view)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,20 +6,28 @@
|
|||||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
@objcMembers public class StackModel: ContainerModel, StackModelProtocol, MoleculeModelProtocol {
|
@objcMembers public class StackModel: ContainerModel, StackModelProtocol, MoleculeModelProtocol {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
static let defaultSpacing: CGFloat = 16.0
|
static let defaultSpacing: CGFloat = 16.0
|
||||||
|
|
||||||
public class var identifier: String {
|
public class var identifier: String {
|
||||||
return "stack"
|
return "stack"
|
||||||
}
|
}
|
||||||
|
|
||||||
public var backgroundColor: Color?
|
public var backgroundColor: Color?
|
||||||
public var molecules: [StackItemModelProtocol & MoleculeModelProtocol]
|
public var molecules: [StackItemModelProtocol & MoleculeModelProtocol]
|
||||||
public var axis: NSLayoutConstraint.Axis = .vertical
|
public var axis: NSLayoutConstraint.Axis = .vertical
|
||||||
public var spacing: CGFloat = StackModel.defaultSpacing
|
public var spacing: CGFloat = StackModel.defaultSpacing
|
||||||
public var useStackSpacingBeforeFirstItem = false
|
public var useStackSpacingBeforeFirstItem = false
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Initializer
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public init(molecules: [StackItemModelProtocol & MoleculeModelProtocol], axis: NSLayoutConstraint.Axis? = nil, spacing: CGFloat? = nil) {
|
public init(molecules: [StackItemModelProtocol & MoleculeModelProtocol], axis: NSLayoutConstraint.Axis? = nil, spacing: CGFloat? = nil) {
|
||||||
self.molecules = molecules
|
self.molecules = molecules
|
||||||
if let axis = axis {
|
if let axis = axis {
|
||||||
@ -30,7 +38,11 @@ import Foundation
|
|||||||
}
|
}
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Keys
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case moleculeName
|
case moleculeName
|
||||||
case backgroundColor
|
case backgroundColor
|
||||||
@ -38,7 +50,11 @@ import Foundation
|
|||||||
case axis
|
case axis
|
||||||
case spacing
|
case spacing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Codec
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
molecules = try typeContainer.decodeModels(codingKey: .molecules)
|
molecules = try typeContainer.decodeModels(codingKey: .molecules)
|
||||||
@ -51,7 +67,7 @@ import Foundation
|
|||||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||||
try super.init(from: decoder)
|
try super.init(from: decoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func encode(to encoder: Encoder) throws {
|
public override func encode(to encoder: Encoder) throws {
|
||||||
try super.encode(to: encoder)
|
try super.encode(to: encoder)
|
||||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|||||||
@ -101,7 +101,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
|
|||||||
|
|
||||||
return estimatedHeight
|
return estimatedHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
open override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||||
return moleculesInfo?.count ?? 0
|
return moleculesInfo?.count ?? 0
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,10 +8,19 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
|
||||||
open class MoleculeStackTemplate: ThreeLayerViewController, TemplateProtocol {
|
open class MoleculeStackTemplate: ThreeLayerViewController, TemplateProtocol {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
var observer: NSKeyValueObservation?
|
var observer: NSKeyValueObservation?
|
||||||
public var templateModel: StackPageTemplateModel?
|
public var templateModel: StackPageTemplateModel?
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Lifecycle
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
open override func handleNewData() {
|
open override func handleNewData() {
|
||||||
topViewOutsideOfScroll = templateModel?.anchorHeader ?? false
|
topViewOutsideOfScroll = templateModel?.anchorHeader ?? false
|
||||||
bottomViewOutsideOfScroll = templateModel?.anchorFooter ?? false
|
bottomViewOutsideOfScroll = templateModel?.anchorFooter ?? false
|
||||||
@ -20,9 +29,9 @@ open class MoleculeStackTemplate: ThreeLayerViewController, TemplateProtocol {
|
|||||||
|
|
||||||
// For subclassing the model.
|
// For subclassing the model.
|
||||||
open func decodeTemplate(using decoder: JSONDecoder, from data: Data) throws -> StackPageTemplateModel {
|
open func decodeTemplate(using decoder: JSONDecoder, from data: Data) throws -> StackPageTemplateModel {
|
||||||
return try decoder.decode(StackPageTemplateModel.self, from: data)
|
return try decoder.decode(StackPageTemplateModel.self, from: data)
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func parsePageJSON() throws {
|
open override func parsePageJSON() throws {
|
||||||
try parseTemplate(json: loadObject?.pageJSON)
|
try parseTemplate(json: loadObject?.pageJSON)
|
||||||
try super.parsePageJSON()
|
try super.parsePageJSON()
|
||||||
@ -48,21 +57,23 @@ open class MoleculeStackTemplate: ThreeLayerViewController, TemplateProtocol {
|
|||||||
|
|
||||||
open override func viewForTop() -> UIView? {
|
open override func viewForTop() -> UIView? {
|
||||||
guard let headerModel = templateModel?.header,
|
guard let headerModel = templateModel?.header,
|
||||||
let molecule = MoleculeObjectMapping.shared()?.createMolecule(headerModel, delegateObject: delegateObjectIVar) else {
|
let molecule = MoleculeObjectMapping.shared()?.createMolecule(headerModel, delegateObject: delegateObjectIVar)
|
||||||
return nil
|
else { return nil }
|
||||||
}
|
|
||||||
return molecule
|
return molecule
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func viewForMiddle() -> UIView? {
|
open override func viewForMiddle() -> UIView? {
|
||||||
guard let moleculeStackModel = templateModel?.moleculeStack else { return nil }
|
guard let moleculeStackModel = templateModel?.moleculeStack else { return nil }
|
||||||
|
|
||||||
// By default: Stack template stack has vertical space before the first item, dynamic stack items have default horizontal padding.
|
// By default: Stack template stack has vertical space before the first item, dynamic stack items have default horizontal padding.
|
||||||
let stack = MoleculeStackView(frame: .zero)
|
let stack = MoleculeStackView(frame: .zero)
|
||||||
moleculeStackModel.useStackSpacingBeforeFirstItem = true
|
moleculeStackModel.useStackSpacingBeforeFirstItem = true
|
||||||
for stackItem in moleculeStackModel.molecules {
|
for stackItem in moleculeStackModel.molecules {
|
||||||
guard let stackItem = stackItem as? MoleculeStackItemModel,
|
guard let stackItem = stackItem as? MoleculeStackItemModel,
|
||||||
stackItem.useHorizontalMargins == nil else { continue }
|
stackItem.useHorizontalMargins == nil
|
||||||
|
else { continue }
|
||||||
|
|
||||||
stackItem.useHorizontalMargins = true
|
stackItem.useHorizontalMargins = true
|
||||||
}
|
}
|
||||||
stack.set(with: moleculeStackModel, delegateObject() as? MVMCoreUIDelegateObject, nil)
|
stack.set(with: moleculeStackModel, delegateObject() as? MVMCoreUIDelegateObject, nil)
|
||||||
@ -71,14 +82,16 @@ open class MoleculeStackTemplate: ThreeLayerViewController, TemplateProtocol {
|
|||||||
|
|
||||||
override open func viewForBottom() -> UIView? {
|
override open func viewForBottom() -> UIView? {
|
||||||
guard let footerModel = templateModel?.footer,
|
guard let footerModel = templateModel?.footer,
|
||||||
let molecule = MoleculeObjectMapping.shared()?.createMolecule(footerModel, delegateObject: delegateObjectIVar) else {
|
let molecule = MoleculeObjectMapping.shared()?.createMolecule(footerModel, delegateObject: delegateObjectIVar)
|
||||||
return nil
|
else { return nil }
|
||||||
}
|
|
||||||
return molecule
|
return molecule
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - cache handling
|
//--------------------------------------------------
|
||||||
|
// MARK: - Cache Handling
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
/// Adds modules from requiredModules() to the MVMCoreViewControllerMapping.requiredModules map.
|
/// Adds modules from requiredModules() to the MVMCoreViewControllerMapping.requiredModules map.
|
||||||
open func updateRequiredModules() {
|
open func updateRequiredModules() {
|
||||||
if let requiredModules = requiredModules(), let pageType = pageType {
|
if let requiredModules = requiredModules(), let pageType = pageType {
|
||||||
|
|||||||
@ -100,14 +100,15 @@ public typealias ButtonAction = (Button) -> ()
|
|||||||
self.model = model
|
self.model = model
|
||||||
|
|
||||||
if let backgroundColor = model.backgroundColor {
|
if let backgroundColor = model.backgroundColor {
|
||||||
self.backgroundColor = backgroundColor.uiColor
|
self.backgroundColor = backgroundColor.uiColor
|
||||||
}
|
}
|
||||||
|
|
||||||
if let model = model as? EnableableModelProtocol {
|
if let model = model as? EnableableModelProtocol {
|
||||||
isEnabled = model.enabled
|
isEnabled = model.enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let model = model as? ButtonModelProtocol else { return }
|
guard let model = model as? ButtonModelProtocol else { return }
|
||||||
|
|
||||||
set(with: model.action, delegateObject: delegateObject, additionalData: additionalData)
|
set(with: model.action, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,6 +147,8 @@ extension Button: MVMCoreViewProtocol {
|
|||||||
|
|
||||||
/// Will be called only once.
|
/// Will be called only once.
|
||||||
open func setupView() {
|
open func setupView() {
|
||||||
|
isAccessibilityElement = true
|
||||||
|
accessibilityTraits = .button
|
||||||
translatesAutoresizingMaskIntoConstraints = false
|
translatesAutoresizingMaskIntoConstraints = false
|
||||||
insetsLayoutMarginsFromSafeArea = false
|
insetsLayoutMarginsFromSafeArea = false
|
||||||
titleLabel?.numberOfLines = 0
|
titleLabel?.numberOfLines = 0
|
||||||
|
|||||||
@ -199,7 +199,7 @@ import UIKit
|
|||||||
caret.accessibilityTraits = .button
|
caret.accessibilityTraits = .button
|
||||||
caret.size = .small(.vertical)
|
caret.size = .small(.vertical)
|
||||||
if let size = caret.size?.dimensions() {
|
if let size = caret.size?.dimensions() {
|
||||||
caret.frame = CGRect(origin: CGPoint.zero, size: size)
|
caret.frame = CGRect(origin: .zero, size: size)
|
||||||
caretViewWidthSizeObject = MFSizeObject(standardSize: size.width, standardiPadPortraitSize: 9)
|
caretViewWidthSizeObject = MFSizeObject(standardSize: size.width, standardiPadPortraitSize: 9)
|
||||||
caretViewHeightSizeObject = MFSizeObject(standardSize: size.height, standardiPadPortraitSize: 16)
|
caretViewHeightSizeObject = MFSizeObject(standardSize: size.height, standardiPadPortraitSize: 16)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
import MVMAnimationFramework
|
import MVMAnimationFramework
|
||||||
|
|
||||||
|
|
||||||
open class ThreeLayerTableViewController: ProgrammaticTableViewController {
|
open class ThreeLayerTableViewController: ProgrammaticTableViewController {
|
||||||
// The three main views
|
// The three main views
|
||||||
private var topView: UIView?
|
private var topView: UIView?
|
||||||
|
|||||||
@ -485,8 +485,8 @@ import UIKit
|
|||||||
// Needed otherwise when subclassed, the extension gets called.
|
// Needed otherwise when subclassed, the extension gets called.
|
||||||
open func moleculeLayoutUpdated(_ molecule: MoleculeViewProtocol) {}
|
open func moleculeLayoutUpdated(_ molecule: MoleculeViewProtocol) {}
|
||||||
open func getIndexPath(for molecule: ListItemModelProtocol & MoleculeModelProtocol) -> IndexPath? { return nil }
|
open func getIndexPath(for molecule: ListItemModelProtocol & MoleculeModelProtocol) -> IndexPath? { return nil }
|
||||||
open func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], indexPath: IndexPath, animation: UITableView.RowAnimation) {}
|
open func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], indexPath: IndexPath, animation: UITableView.RowAnimation) { }
|
||||||
open func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], animation: UITableView.RowAnimation) {}
|
open func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], animation: UITableView.RowAnimation) { }
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - MVMCoreUIDetailViewProtocol
|
// MARK: - MVMCoreUIDetailViewProtocol
|
||||||
|
|||||||
@ -8,7 +8,11 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
|
||||||
open class Container: View, ContainerProtocol {
|
open class Container: View, ContainerProtocol {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public var view: UIView?
|
public var view: UIView?
|
||||||
let containerHelper = ContainerHelper()
|
let containerHelper = ContainerHelper()
|
||||||
@ -17,10 +21,15 @@ open class Container: View, ContainerProtocol {
|
|||||||
get { return model as? ContainerModelProtocol }
|
get { return model as? ContainerModelProtocol }
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK:- MoleculeViewProtocol
|
//--------------------------------------------------
|
||||||
|
// MARK: - MoleculeViewProtocol
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
override open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
override open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
super.set(with: model, delegateObject, additionalData)
|
super.set(with: model, delegateObject, additionalData)
|
||||||
|
|
||||||
guard let containerModel = model as? ContainerModelProtocol else { return }
|
guard let containerModel = model as? ContainerModelProtocol else { return }
|
||||||
|
|
||||||
containerHelper.set(with: containerModel, for: view as? MVMCoreUIViewConstrainingProtocol)
|
containerHelper.set(with: containerModel, for: view as? MVMCoreUIViewConstrainingProtocol)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +38,10 @@ open class Container: View, ContainerProtocol {
|
|||||||
(view as? MoleculeViewProtocol)?.reset()
|
(view as? MoleculeViewProtocol)?.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK:- ContainerProtocol
|
//--------------------------------------------------
|
||||||
|
// MARK: - ContainerProtocol
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
open func alignHorizontal(_ alignment: UIStackView.Alignment) {
|
open func alignHorizontal(_ alignment: UIStackView.Alignment) {
|
||||||
containerHelper.alignHorizontal(alignment)
|
containerHelper.alignHorizontal(alignment)
|
||||||
}
|
}
|
||||||
@ -45,15 +57,17 @@ open class Container: View, ContainerProtocol {
|
|||||||
|
|
||||||
// MARK: - MVMCoreViewProtocol
|
// MARK: - MVMCoreViewProtocol
|
||||||
public extension Container {
|
public extension Container {
|
||||||
|
|
||||||
override func updateView(_ size: CGFloat) {
|
override func updateView(_ size: CGFloat) {
|
||||||
super.updateView(size)
|
super.updateView(size)
|
||||||
(view as? MVMCoreViewProtocol)?.updateView(size)
|
(view as? MVMCoreViewProtocol)?.updateView(size)
|
||||||
containerHelper.updateViewMargins(self, model: containerModel, size: size)
|
containerHelper.updateViewMargins(self, model: containerModel, size: size)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Will be called only once.
|
/// Will be called only once.
|
||||||
override func setupView() {
|
override func setupView() {
|
||||||
super.setupView()
|
super.setupView()
|
||||||
|
isAccessibilityElement = false
|
||||||
backgroundColor = .clear
|
backgroundColor = .clear
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user