From 6303c3f92ddc042dcb34e9307af5ca2fbdf66e66 Mon Sep 17 00:00:00 2001 From: panxi Date: Thu, 21 Nov 2019 13:15:27 -0500 Subject: [PATCH] update label model --- MVMCoreUI.xcodeproj/project.pbxproj | 14 ++- MVMCoreUI/Atoms/Views/Label.swift | 117 +++++++++++++++++- MVMCoreUI/Atoms/Views/LabelModel.swift | 16 --- .../LabelModel/LabelAttributeModel.swift | 64 ++++++++++ .../Atoms/Views/LabelModel/LabelModel.swift | 27 ++++ MVMCoreUI/Atoms/Views/MultiProgress.swift | 10 +- .../Atoms/Views/MultiProgressModel.swift | 8 +- MVMCoreUI/Atoms/Views/ProgressBarModel.swift | 5 +- 8 files changed, 228 insertions(+), 33 deletions(-) delete mode 100644 MVMCoreUI/Atoms/Views/LabelModel.swift create mode 100644 MVMCoreUI/Atoms/Views/LabelModel/LabelAttributeModel.swift create mode 100644 MVMCoreUI/Atoms/Views/LabelModel/LabelModel.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 5c000157..65ff9299 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -54,6 +54,7 @@ 9455B19C234F8A0400A574DB /* MVMAnimationFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9455B19B234F8A0400A574DB /* MVMAnimationFramework.framework */; }; 946EE1BA237B66D80036751F /* ModelHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 946EE1B9237B66D80036751F /* ModelHelper.swift */; }; 948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 948DB67D2326DCD90011F916 /* MultiProgress.swift */; }; + 94C2D9842386F3F80006CF46 /* LabelAttributeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C2D9832386F3F80006CF46 /* LabelAttributeModel.swift */; }; D206997721FB8A0B00CAE0DE /* MVMCoreUINavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; }; D206997821FB8A0B00CAE0DE /* MVMCoreUINavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = D206997621FB8A0B00CAE0DE /* MVMCoreUINavigationController.m */; }; D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */; }; @@ -273,6 +274,7 @@ 9455B19B234F8A0400A574DB /* MVMAnimationFramework.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MVMAnimationFramework.framework; path = ../SharedFrameworks/MVMAnimationFramework.framework; sourceTree = ""; }; 946EE1B9237B66D80036751F /* ModelHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelHelper.swift; sourceTree = ""; }; 948DB67D2326DCD90011F916 /* MultiProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiProgress.swift; sourceTree = ""; }; + 94C2D9832386F3F80006CF46 /* LabelAttributeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelAttributeModel.swift; sourceTree = ""; }; D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUINavigationController.h; sourceTree = ""; }; D206997621FB8A0B00CAE0DE /* MVMCoreUINavigationController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUINavigationController.m; sourceTree = ""; }; D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = ""; }; @@ -507,6 +509,15 @@ path = Extensions; sourceTree = ""; }; + 94C2D9822386F3E30006CF46 /* LabelModel */ = { + isa = PBXGroup; + children = ( + 01EB368823609801006832FA /* LabelModel.swift */, + 94C2D9832386F3F80006CF46 /* LabelAttributeModel.swift */, + ); + path = LabelModel; + sourceTree = ""; + }; D224798823142BF2003FCCF9 /* SwitchMolecules */ = { isa = PBXGroup; children = ( @@ -837,7 +848,7 @@ D22D1F45220496A30077CEC0 /* MVMCoreUISwitch.m */, DBC4391C2245232D001AB423 /* LabelWithInternalButton.swift */, DB891E822253FA8500022516 /* Label.swift */, - 01EB368823609801006832FA /* LabelModel.swift */, + 94C2D9822386F3E30006CF46 /* LabelModel */, 0198F7A02256A80A0066C936 /* MFRadioButton.h */, 0198F7A22256A80A0066C936 /* MFRadioButton.m */, 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */, @@ -1210,6 +1221,7 @@ D274CA332236A78900B01B62 /* StandardFooterView.swift in Sources */, D29DF2BF21E7BEA4003B2FB9 /* MVMCoreUITabBarPageControlViewController.m in Sources */, D29DF28321E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.m in Sources */, + 94C2D9842386F3F80006CF46 /* LabelAttributeModel.swift in Sources */, D206997821FB8A0B00CAE0DE /* MVMCoreUINavigationController.m in Sources */, 944589212385D6E900DE9FD4 /* DashLineModel.swift in Sources */, D29DF27A21E7A533003B2FB9 /* MVMCoreUISession.m in Sources */, diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 6b013f82..2cd23405 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -12,7 +12,8 @@ import MVMCore public typealias ActionBlock = () -> () -@objcMembers open class Label: UILabel, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol, MFButtonProtocol { +@objcMembers open class Label: UILabel, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol, MFButtonProtocol, ModelMoleculeViewProtocol { + //------------------------------------------------------ // MARK: - Properties //------------------------------------------------------ @@ -212,8 +213,120 @@ public typealias ActionBlock = () -> () } } + enum LabelAlignment: String { + case center + case right + case left + } + + public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + clauses = [] + guard let labelModel = model as? LabelModel else { return } + attributedText = nil + text = labelModel.text + Label.setLabel(self, withHTML: labelModel.html) + let alignment = LabelAlignment(rawValue: labelModel.textAlignment ?? "") + switch alignment { + case .center: + textAlignment = .center + case .right: + textAlignment = .right + default: + textAlignment = .left + } + + + makeWholeViewClickable = labelModel.makeWholeViewClickable ?? false + if let backgroundColorHex = labelModel.backgroundColor, !backgroundColorHex.isEmpty { + backgroundColor = UIColor.mfGet(forHex: backgroundColorHex) + } + if let accessibilityText = labelModel.accessibilityText { + accessibilityLabel = accessibilityText + } + if let fontStyle = labelModel.fontStyle { + MFStyler.styleLabel(self, withStyle: fontStyle) + } else { + let fontSize = labelModel.fontSize as? CGFloat + if let fontName = labelModel.fontName { + font = MFFonts.mfFont(withName: fontName, size: fontSize ?? font.pointSize) + } else if let fontSize = fontSize { + font = font.withSize(fontSize) + } + } + + if let textColorHex = labelModel.textColor, !textColorHex.isEmpty { + textColor = UIColor.mfGet(forHex: textColorHex) + } + + if let attributes = labelModel.attributes, let labelText = text { + let attributedString = NSMutableAttributedString(string: labelText, attributes: [NSAttributedString.Key.font: font as UIFont, NSAttributedString.Key.foregroundColor: textColor as UIColor]) + for attribute in attributes { + guard let attributeStyle = attribute.type, let location = attribute.location, let length = attribute.length else { continue } + let range = NSRange(location: location, length: length) + switch attributeStyle { + case .underline: + attributedString.addAttribute(.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: range) + case .strikethrough: + attributedString.addAttribute(.strikethroughStyle, value: NSUnderlineStyle.thick.rawValue, range: range) + attributedString.addAttribute(.baselineOffset, value: 0, range: range) + case .color: + if let colorHex = attribute.textColor, !colorHex.isEmpty { + attributedString.removeAttribute(.foregroundColor, range: range) + attributedString.addAttribute(.foregroundColor, value: UIColor.mfGet(forHex: colorHex), range: range) + } + case .image: + var fontSize = font.pointSize + if let attributeSize = attribute.size { + fontSize = attributeSize + } + let imageName = attribute.name ?? "externalLink" + let imageAttachment: NSTextAttachment + + if let url = attribute.URL { + imageAttachment = Label.getTextAttachmentFrom(url: url, dimension: fontSize, label: self) + } else { + imageAttachment = Label.getTextAttachmentImage(name: imageName, dimension: fontSize) + } + let mutableString = NSMutableAttributedString() + mutableString.append(NSAttributedString(attachment: imageAttachment)) + attributedString.insert(mutableString, at: location) + case .font: + if let fontStyle = attribute.style { + let styles = MFStyler.styleGetAttributedString("0", withStyle: fontStyle) + attributedString.removeAttribute(.font, range: range) + attributedString.removeAttribute(.foregroundColor, range: range) + attributedString.addAttributes(styles.attributes(at: 0, effectiveRange: nil), range: range) + } else { + let fontSize = attribute.size + var font: UIFont? + + if let fontName = attribute.name { + font = MFFonts.mfFont(withName: fontName, size: fontSize ?? self.font.pointSize) + } else if let fontSize = fontSize { + font = self.font.withSize(fontSize) + } + if let font = font { + attributedString.removeAttribute(.font, range: range) + attributedString.addAttribute(.font, value: font, range: range) + } + } + case .action: + addActionAttributes(range: range, string: attributedString) +// if let actionBlock = createActionBlockFor(actionMap: attribute, additionalData: additionalData, delegateObject: delegateObject) { +// appendActionableClause(range: range, actionBlock: actionBlock) +// } + default: + continue + } + } + } + + originalAttributedString = attributedText + hero = labelModel.hero + } + @objc public static func setUILabel(_ label: UILabel?, withJSON json: [AnyHashable: Any]?, delegate: DelegateObject?, additionalData: [AnyHashable: Any]?) { - //LabelModel() + guard let label = label else { return } label.attributedText = nil label.text = json?.optionalStringForKey(KeyText) diff --git a/MVMCoreUI/Atoms/Views/LabelModel.swift b/MVMCoreUI/Atoms/Views/LabelModel.swift deleted file mode 100644 index e5de1ccf..00000000 --- a/MVMCoreUI/Atoms/Views/LabelModel.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// Label.swift -// MVMCoreUI -// -// Created by Suresh, Kamlesh on 10/3/19. -// Copyright © 2019 Suresh, Kamlesh. All rights reserved. -// - - -import Foundation - -@objcMembers public class LabelModel: MoleculeProtocol { - public static var identifier: String = "label" - public var moleculeName: String? - public var text: String? -} diff --git a/MVMCoreUI/Atoms/Views/LabelModel/LabelAttributeModel.swift b/MVMCoreUI/Atoms/Views/LabelModel/LabelAttributeModel.swift new file mode 100644 index 00000000..e4388ea5 --- /dev/null +++ b/MVMCoreUI/Atoms/Views/LabelModel/LabelAttributeModel.swift @@ -0,0 +1,64 @@ +// +// LabelAttributeModel.swift +// MVMCoreUI +// +// Created by Ryan on 11/21/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers open class LabelAttributeModel: Codable { + enum ModelType: String, Codable { + case underline + case strikethrough + case color + case image + case font + case action + } + + var type: ModelType? + var location: Int? + var length: Int? + var textColor: String? + var style: String? + var size: CGFloat? + var name: String? + var URL: String? + + enum CodingKeys: String, CodingKey { + case type + case location + case length + case textColor + case style + case size + case name + case URL + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + self.type = try typeContainer.decodeIfPresent(ModelType.self, forKey: .type) + self.location = try typeContainer.decodeIfPresent(Int.self, forKey: .location) + self.length = try typeContainer.decodeIfPresent(Int.self, forKey: .length) + self.textColor = try typeContainer.decodeIfPresent(String.self, forKey: .textColor) + self.style = try typeContainer.decodeIfPresent(String.self, forKey: .style) + self.size = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .size) + self.name = try typeContainer.decodeIfPresent(String.self, forKey: .name) + self.URL = try typeContainer.decodeIfPresent(String.self, forKey: .URL) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(type, forKey: .type) + try container.encodeIfPresent(location, forKey: .location) + try container.encodeIfPresent(length, forKey: .length) + try container.encodeIfPresent(textColor, forKey: .textColor) + try container.encodeIfPresent(style, forKey: .style) + try container.encodeIfPresent(size, forKey: .size) + try container.encodeIfPresent(name, forKey: .name) + try container.encodeIfPresent(URL, forKey: .URL) + } +} diff --git a/MVMCoreUI/Atoms/Views/LabelModel/LabelModel.swift b/MVMCoreUI/Atoms/Views/LabelModel/LabelModel.swift new file mode 100644 index 00000000..376166ed --- /dev/null +++ b/MVMCoreUI/Atoms/Views/LabelModel/LabelModel.swift @@ -0,0 +1,27 @@ +// +// Label.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 10/3/19. +// Copyright © 2019 Suresh, Kamlesh. All rights reserved. +// + + +import Foundation + +@objcMembers public class LabelModel: MoleculeProtocol { + public static var identifier: String = "label" + public var moleculeName: String? + public var text: String + public var accessibilityText: String? + public var textColor: String? + public var backgroundColor: String? + public var fontStyle: String? + public var fontName: String? + public var fontSize: CGFloat? + public var textAlignment: String? + public var attributes: [LabelAttributeModel]? + public var html: String? + public var hero: Int? + public var makeWholeViewClickable: Bool? +} diff --git a/MVMCoreUI/Atoms/Views/MultiProgress.swift b/MVMCoreUI/Atoms/Views/MultiProgress.swift index 0e911e37..f6809e53 100644 --- a/MVMCoreUI/Atoms/Views/MultiProgress.swift +++ b/MVMCoreUI/Atoms/Views/MultiProgress.swift @@ -21,18 +21,14 @@ import UIKit } var previous: UIView? for progressObject in progressList! { - guard progressObject.progress ?? 0.0 > 0.0 else { + guard progressObject.progress > 0.0 else { continue } let view = MFView(frame: .zero) view.translatesAutoresizingMaskIntoConstraints = false addSubview(view) - var color = UIColor.mfCerulean() - if let colorString = progressObject.color { - color = UIColor.mfGet(forHex: colorString) - } - view.backgroundColor = color - view.widthAnchor.constraint(equalTo: widthAnchor, multiplier: progressObject.progress ?? 0).isActive = true + view.backgroundColor = UIColor.mfGet(forHex: progressObject.color) + view.widthAnchor.constraint(equalTo: widthAnchor, multiplier: progressObject.progress).isActive = true view.leadingAnchor.constraint(equalTo: previous?.trailingAnchor ?? leadingAnchor).isActive = true previous = view NSLayoutConstraint.constraintPinSubview(view, pinTop: true, pinBottom: true, pinLeft: false, pinRight: false) diff --git a/MVMCoreUI/Atoms/Views/MultiProgressModel.swift b/MVMCoreUI/Atoms/Views/MultiProgressModel.swift index 156f71a0..d63183e4 100644 --- a/MVMCoreUI/Atoms/Views/MultiProgressModel.swift +++ b/MVMCoreUI/Atoms/Views/MultiProgressModel.swift @@ -10,14 +10,14 @@ import Foundation @objcMembers public class SingleProgressBarModel: Codable { - var progress: CGFloat? - var color: String? + var progress: CGFloat + var color: String } @objcMembers public class MultiProgressBarModel: MoleculeProtocol { public static var identifier: String = "multiProgressBar" public var moleculeName: String - public var progressList: [SingleProgressBarModel]? + public var progressList: [SingleProgressBarModel] public var thickness: CGFloat? public var roundedRect: Bool? @@ -32,7 +32,7 @@ import Foundation let typeContainer = try decoder.container(keyedBy: CodingKeys.self) self.moleculeName = try typeContainer.decode(String.self, forKey: .moleculeName) - self.progressList = try typeContainer.decodeIfPresent([SingleProgressBarModel].self, forKey: .progressList) + self.progressList = try typeContainer.decode([SingleProgressBarModel].self, forKey: .progressList) self.thickness = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .thickness) self.roundedRect = try typeContainer.decodeIfPresent(Bool.self, forKey: .roundedRect) } diff --git a/MVMCoreUI/Atoms/Views/ProgressBarModel.swift b/MVMCoreUI/Atoms/Views/ProgressBarModel.swift index b48f0321..3450fc87 100644 --- a/MVMCoreUI/Atoms/Views/ProgressBarModel.swift +++ b/MVMCoreUI/Atoms/Views/ProgressBarModel.swift @@ -15,7 +15,7 @@ import Foundation public var isRounded: Bool? public var thickness: CGFloat? ///from 0 to 100 - public var percentage: Float? + public var percentage: Float public var progressColor: String? public var backgroundColor: String? @@ -29,12 +29,11 @@ import Foundation } required public init(from decoder: Decoder) throws { - let typeContainer = try decoder.container(keyedBy: CodingKeys.self) self.moleculeName = try typeContainer.decode(String.self, forKey: .moleculeName) self.isRounded = try typeContainer.decodeIfPresent(Bool.self, forKey: .isRounded) self.thickness = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .thickness) - self.percentage = try typeContainer.decodeIfPresent(Float.self, forKey: .percentage) + self.percentage = try typeContainer.decode(Float.self, forKey: .percentage) self.progressColor = try typeContainer.decodeIfPresent(String.self, forKey: .progressColor) self.backgroundColor = try typeContainer.decodeIfPresent(String.self, forKey: .backgroundColor)