diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index dbee02e2..8efde844 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -67,6 +67,9 @@ 94C2D9A723872DA90006CF46 /* LabelAttributeColorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C2D9A623872DA90006CF46 /* LabelAttributeColorModel.swift */; }; 94C2D9A923872E5E0006CF46 /* LabelAttributeImageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C2D9A823872E5E0006CF46 /* LabelAttributeImageModel.swift */; }; 94C2D9AB23872EB50006CF46 /* LabelAttributeActionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C2D9AA23872EB50006CF46 /* LabelAttributeActionModel.swift */; }; + C695A69423C9909000BFB94E /* DoughnutChartModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C695A69323C9909000BFB94E /* DoughnutChartModel.swift */; }; + C695A69623C990BC00BFB94E /* DoughnutChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = C695A69523C990BC00BFB94E /* DoughnutChart.swift */; }; + C695A69823C990C200BFB94E /* DoughnutChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C695A69723C990C200BFB94E /* DoughnutChartView.swift */; }; D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */; }; D213347723843825008E41B3 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = D213347623843825008E41B3 /* Line.swift */; }; D21EE53C23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21EE53B23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift */; }; @@ -307,6 +310,9 @@ 94C2D9A623872DA90006CF46 /* LabelAttributeColorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelAttributeColorModel.swift; sourceTree = ""; }; 94C2D9A823872E5E0006CF46 /* LabelAttributeImageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelAttributeImageModel.swift; sourceTree = ""; }; 94C2D9AA23872EB50006CF46 /* LabelAttributeActionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelAttributeActionModel.swift; sourceTree = ""; }; + C695A69323C9909000BFB94E /* DoughnutChartModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DoughnutChartModel.swift; sourceTree = ""; }; + C695A69523C990BC00BFB94E /* DoughnutChart.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DoughnutChart.swift; sourceTree = ""; }; + C695A69723C990C200BFB94E /* DoughnutChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DoughnutChartView.swift; sourceTree = ""; }; D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = ""; }; D213347623843825008E41B3 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = ""; }; D21EE53B23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSLayoutConstraintAxis+Extension.swift"; sourceTree = ""; }; @@ -530,6 +536,7 @@ 01EB368723609801006832FA /* Molecules */ = { isa = PBXGroup; children = ( + C695A69323C9909000BFB94E /* DoughnutChartModel.swift */, 01EB368923609801006832FA /* ListItemModel.swift */, 01EB368A23609801006832FA /* MoleculeStackItemModel.swift */, 01EB368B23609801006832FA /* MoleculeStackModel.swift */, @@ -542,6 +549,14 @@ path = Molecules; sourceTree = ""; }; + 0A5D59C323AD488600EFD9E9 /* Protocols */ = { + isa = PBXGroup; + children = ( + 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */, + ); + path = Protocols; + sourceTree = ""; + }; 0AA33B322398134B0067DD0F /* Primitive Models */ = { isa = PBXGroup; children = ( @@ -580,14 +595,6 @@ name = "Recovered References"; sourceTree = ""; }; - 0A5D59C323AD488600EFD9E9 /* Protocols */ = { - isa = PBXGroup; - children = ( - 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */, - ); - path = Protocols; - sourceTree = ""; - }; D213347423842FE3008E41B3 /* Controllers */ = { isa = PBXGroup; children = ( @@ -785,6 +792,8 @@ D2FB151A23A2B65B00C20E10 /* MoleculeContainer.swift */, 017BEB47236230DB0024EF95 /* MoleculeViewProtocol.swift */, 017BEB49236235BA0024EF95 /* ModelMoleculeViewProtocol.swift */, + C695A69523C990BC00BFB94E /* DoughnutChart.swift */, + C695A69723C990C200BFB94E /* DoughnutChartView.swift */, ); path = Molecules; sourceTree = ""; @@ -1296,6 +1305,7 @@ D2A5145F2211DDC100345BFB /* MoleculeStackView.swift in Sources */, D29DF27621E79E81003B2FB9 /* MVMCoreUILoggingHandler.m in Sources */, D29DF24D21E6A177003B2FB9 /* MFTextField.m in Sources */, + C695A69623C990BC00BFB94E /* DoughnutChart.swift in Sources */, 94C2D9AB23872EB50006CF46 /* LabelAttributeActionModel.swift in Sources */, 017BEB4023620A230024EF95 /* TextFieldModel.swift in Sources */, D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */, @@ -1396,6 +1406,7 @@ D2B18B922361E65A00A9AEDC /* CoreUIObject.swift in Sources */, D29DF2BE21E7BEA4003B2FB9 /* TopTabbar.m in Sources */, D2A514632213643100345BFB /* MoleculeStackCenteredTemplate.swift in Sources */, + C695A69423C9909000BFB94E /* DoughnutChartModel.swift in Sources */, D29DF32421ED0DA2003B2FB9 /* TextButtonView.m in Sources */, D29DF29E21E7AE3B003B2FB9 /* MFStyler.m in Sources */, D2A514592211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.m in Sources */, @@ -1404,6 +1415,7 @@ 0105618D224BBE7700E1557D /* FormValidator.swift in Sources */, 01509D912327ECE600EF99AA /* CornerLabels.swift in Sources */, D22D1F1B220341F60077CEC0 /* MVMCoreUICheckBox.m in Sources */, + C695A69823C990C200BFB94E /* DoughnutChartView.swift in Sources */, D29DF2CB21E7BFCC003B2FB9 /* MFSizeThreshold.m in Sources */, 946EE1BA237B66D80036751F /* ModelHelper.swift in Sources */, 01509D932327ECFB00EF99AA /* ProgressBar.swift in Sources */, diff --git a/MVMCoreUI/Models/Molecules/DoughnutChartModel.swift b/MVMCoreUI/Models/Molecules/DoughnutChartModel.swift new file mode 100644 index 00000000..f6a1efb8 --- /dev/null +++ b/MVMCoreUI/Models/Molecules/DoughnutChartModel.swift @@ -0,0 +1,85 @@ +// +// DoughnutChartModel.swift +// MVMCoreUI +// +// Created by Murugan, Vimal on 10/01/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers public class DoughnutChartModel: MoleculeProtocol { + + public var backgroundColor: String? + public static var identifier: String = "doughnutChart" + public var title: LabelModel? + public var subtitle: LabelModel? + public var sections: [ChartItemModel] + public var lineWidth: CGFloat = 30.0 + public var lineGap: CGFloat = 0.05 //For 3px gap + public var spaceRequired = true + + enum CodingKeys: String, CodingKey { + case list + case title + case subtitle + case sections + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + self.title = try typeContainer.decodeMoleculeIfPresent(codingKey: .title) as? LabelModel + self.subtitle = try typeContainer.decodeMoleculeIfPresent(codingKey: .subtitle) as? LabelModel + //self.sections = try typeContainer.decodeMolecules(codingKey: .sections) as! [ChartItemModel] + + //TODO: Hasve to check with scott + self.sections = [] + guard var container = try? typeContainer.nestedUnkeyedContainer(forKey: .sections) else { + return + } + var sections = [ChartItemModel]() + while !container.isAtEnd { + if let element = try container + .decodeIfPresent(ChartItemModel.self) { + sections.append(element) + } + } + self.sections = sections + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeModelIfPresent(title, forKey: .title) + try container.encodeModelIfPresent(subtitle, forKey: .subtitle) + try container.encodeModels(sections as [Model], forKey: .sections) + } +} + + +@objcMembers public class ChartItemModel: MoleculeProtocol { + public var backgroundColor: String? + public var label: LabelModel + public var percent: CGFloat + public var color: String + public static var identifier: String = "chartItem" + + enum CodingKeys: String, CodingKey { + case label + case percent + case color + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + self.label = try typeContainer.decodeMolecule(codingKey: .label) as! LabelModel + self.percent = try typeContainer.decode(CGFloat.self, forKey: .percent) + self.color = try typeContainer.decode(String.self, forKey: .color) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeModel(label, forKey: .label) + try container.encode(percent, forKey: .percent) + try container.encode(color, forKey: .color) + } +} diff --git a/MVMCoreUI/Molecules/DoughnutChart.swift b/MVMCoreUI/Molecules/DoughnutChart.swift new file mode 100644 index 00000000..08bdefb1 --- /dev/null +++ b/MVMCoreUI/Molecules/DoughnutChart.swift @@ -0,0 +1,179 @@ +// +// DoughnutChart.swift +// MVMCoreUI +// +// Created by Murugan, Vimal on 07/01/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import UIKit + +open class DoughnutChart: View, MVMCoreUIViewConstrainingProtocol { + + var containerView = MVMCoreUICommonViewsUtility.commonView() + var containerLayer = CALayer() + var titleLabel = Label.commonLabelH3(true) + var subTitleLabel = Label.commonLabelB2(true) + var doughnutChartModel: DoughnutChartModel? { + get { return model as? DoughnutChartModel } + } + var labelContainer = ViewConstrainingView.empty() + var heightConstraint: NSLayoutConstraint? + + private var sizeObject = MFStyler.sizeObjectGeneric(forCurrentDevice: 150)! + //private var lineSizeObject = MFStyler.sizeObjectGeneric(forCurrentDevice: 30)! + + var height: CGFloat = 150 { + didSet { + if height != oldValue { + sizeObject = MFStyler.sizeObjectGeneric(forCurrentDevice: height)! + updateContainer() + drawGraph() + } + } + } + + open override func updateView(_ size: CGFloat) { + super.updateView(size) + titleLabel.updateView(size) + subTitleLabel.updateView(size) + updateContainer() + drawGraph() + } + + open override func reset() { + super.reset() + titleLabel.reset() + subTitleLabel.reset() + clearLayers() + } + + public func setAsMolecule() { + titleLabel.setAsMolecule() + subTitleLabel.setAsMolecule() + } + + open override func setupView() { + super.setupView() + guard containerView.superview == nil else { + return + } + addSubview(containerView) + addSubview(labelContainer) + + labelContainer.addSubview(titleLabel) + labelContainer.addSubview(subTitleLabel) + titleLabel.textAlignment = .center + subTitleLabel.textAlignment = .center + + //Make label font size to adjust width if label content is high + titleLabel.numberOfLines = 1 + titleLabel.adjustsFontSizeToFitWidth = true + + containerView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true + containerView.topAnchor.constraint(equalTo: topAnchor).isActive = true + bottomAnchor.constraint(equalTo: containerView.bottomAnchor).isActive = true + trailingAnchor.constraint(equalTo: containerView.trailingAnchor).isActive = true + containerView.layer.addSublayer(containerLayer) + heightConstraint = containerView.heightAnchor.constraint(equalToConstant: + sizeObject.getValueBasedOnApplicationWidth()) + heightConstraint?.isActive = true + containerView.widthAnchor.constraint(equalTo: containerView.heightAnchor).isActive = true + + labelContainer.leftPin = labelContainer.leftAnchor.constraint(greaterThanOrEqualTo: containerView.leftAnchor, constant: lineWidth()) + labelContainer.leftPin?.isActive = true + labelContainer.topPin = labelContainer.topAnchor.constraint(greaterThanOrEqualTo: containerView.topAnchor, constant: lineWidth()) + labelContainer.topPin?.isActive = true + labelContainer.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true + labelContainer.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true + + NSLayoutConstraint.constraintPinSubview(titleLabel, pinTop: true, pinBottom: false, pinLeft: true, pinRight: true) + NSLayoutConstraint.constraintPinSubview(subTitleLabel, pinTop: false, pinBottom: true, pinLeft: true, pinRight: true) + _ = NSLayoutConstraint(pinFirstView: titleLabel, toSecondView: subTitleLabel, withConstant: 0, directionVertical: true) + //Rotate view for initial draw + containerLayer.transform = CATransform3DMakeRotation(1 * .pi, 0.0, 0.0, 1.0) + + } + + open override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + super.setWithModel(model, delegateObject, additionalData) + clearLayers() + guard let doughnutChartModel = model as? DoughnutChartModel else { + return + } + titleLabel.setWithModel(doughnutChartModel.title, delegateObject, additionalData) + subTitleLabel.setWithModel(doughnutChartModel.subtitle, delegateObject, additionalData) + titleLabel.textAlignment = .center + subTitleLabel.textAlignment = .center + //lineSizeObject = MFStyler.sizeObjectGeneric(forCurrentDevice: doughnutChartModel.lineWidth)! + updateLabelContainer() + drawGraph() + } + + func drawGraph() { + clearLayers() + let widthHeight = sizeObject.getValueBasedOnApplicationWidth() + containerLayer.frame = CGRect(x: 0, y: 0, + width: widthHeight, + height: widthHeight) + if let doughnutChart = doughnutChartModel { + var prevPercent: CGFloat = 0.0 + //If Single item in array. We don't need gap + doughnutChartModel?.lineGap = (doughnutChart.sections.count == 1) ? 0.0 : doughnutChart.lineGap + for model in doughnutChart.sections { + prevPercent += drawBar(model, prevPercent, doughnutChart.spaceRequired, doughnutChart.lineGap) + } + } + } + + func drawBar(_ chartModel: ChartItemModel, _ prevPercent: CGFloat, _ spaceRequired: Bool, _ lineGap: CGFloat) -> CGFloat { + + let shapeLayer = CAShapeLayer() + shapeLayer.frame = containerLayer.frame + shapeLayer.lineWidth = lineWidth() + //lineSizeObject.getValueBasedOnApplicationWidth() + shapeLayer.fillColor = nil + shapeLayer.strokeColor = UIColor.mfGet(forHex: chartModel.color).cgColor + + let arcCenter = shapeLayer.position + let radius = shapeLayer.bounds.size.width / 2.0 - lineWidth()/2.0 + //lineSizeObject.getValueBasedOnApplicationWidth() / 2.0 + let clockwise = true + + let value: CGFloat = chartModel.percent + let gap: CGFloat = spaceRequired ? lineGap : 0.0 + let startAngle = ((prevPercent / 100.0) * 2 * .pi) - (0.5 * .pi) + let endAngle = ((value / 100.0) * 2 * .pi) + startAngle - gap + let circlePath = UIBezierPath(arcCenter: arcCenter, + radius: radius, + startAngle: startAngle, + endAngle: endAngle, + clockwise: clockwise) + + shapeLayer.path = circlePath.cgPath + containerLayer.addSublayer(shapeLayer) + return value + } + + func clearLayers() { + containerLayer.sublayers?.forEach({ $0.removeFromSuperlayer() }) + } + + func updateContainer() { + heightConstraint?.constant = sizeObject.getValueBasedOnApplicationWidth() + updateLabelContainer() + setNeedsDisplay() + } + + func lineWidth() -> CGFloat { + return doughnutChartModel?.lineWidth ?? 30 + //lineSizeObject.getValueBasedOnApplicationWidth() + 5 + } + + func updateLabelContainer() { + labelContainer.leftPin?.constant = lineWidth() + labelContainer.topPin?.constant = lineWidth() + labelContainer.setNeedsDisplay() + } + +} diff --git a/MVMCoreUI/Molecules/DoughnutChartView.swift b/MVMCoreUI/Molecules/DoughnutChartView.swift new file mode 100644 index 00000000..ebe77200 --- /dev/null +++ b/MVMCoreUI/Molecules/DoughnutChartView.swift @@ -0,0 +1,179 @@ +// +// DoughnutChartView.swift +// MVMCoreUI +// +// Created by Murugan, Vimal on 26/12/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers open class DoughnutChartView: View { + + var doughnutChart = DoughnutChart(frame: CGRect.zero) + var colorLablesStack = ColorViewLabelsStack() + var container = MVMCoreUICommonViewsUtility.commonView() + var doughnutChartModel: DoughnutChartModel? { + get { return model as? DoughnutChartModel } + } + + open override func setupView() { + super.setupView() + guard container.superview == nil else { + return + } + + addSubview(container) + doughnutChart.translatesAutoresizingMaskIntoConstraints = false + container.addSubview(doughnutChart) + colorLablesStack.translatesAutoresizingMaskIntoConstraints = false + container.addSubview(colorLablesStack) + + NSLayoutConstraint.constraintPinSubview(container, pinTop: true, pinBottom: true, pinLeft: true, pinRight: true) + doughnutChart.leadingAnchor.constraint(equalTo: container.leadingAnchor).isActive = true + doughnutChart.topAnchor.constraint(equalTo: container.topAnchor, constant: PaddingFour).isActive = true + container.bottomAnchor.constraint(greaterThanOrEqualTo: doughnutChart.bottomAnchor).isActive = true + + let containerBottomAnchor = container.bottomAnchor.constraint(equalTo: doughnutChart.bottomAnchor) + containerBottomAnchor.priority = UILayoutPriority(rawValue: 200) + containerBottomAnchor.isActive = true + + let colorLablesBottomAnchor = container.bottomAnchor.constraint(equalTo: colorLablesStack.bottomAnchor) + colorLablesBottomAnchor.priority = UILayoutPriority(rawValue: 204) + colorLablesBottomAnchor.isActive = true + + let colorLablesTopAnchor = colorLablesStack.topAnchor.constraint(equalTo: doughnutChart.topAnchor) + colorLablesTopAnchor.priority = UILayoutPriority(rawValue: 204) + colorLablesTopAnchor.isActive = true + + colorLablesStack.topAnchor.constraint(greaterThanOrEqualTo: doughnutChart.topAnchor).isActive = true + container.bottomAnchor.constraint(greaterThanOrEqualTo: colorLablesStack.bottomAnchor).isActive = true + container.trailingAnchor.constraint(greaterThanOrEqualTo: colorLablesStack.trailingAnchor).isActive = true + + let centerY = colorLablesStack.centerYAnchor.constraint(equalTo: doughnutChart.centerYAnchor) + centerY.priority = .defaultLow + centerY.isActive = true + + colorLablesStack.leadingAnchor.constraint(equalTo: doughnutChart.trailingAnchor, constant: PaddingThree).isActive = true + colorLablesStack.backgroundColor = UIColor.clear + + } + + open override func updateView(_ size: CGFloat) { + super.updateView(size) + doughnutChart.updateView(size) + colorLablesStack.updateView(size) + } + + open override func reset() { + super.reset() + colorLablesStack.reset() + } + + open override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + super.setWithModel(model, delegateObject, additionalData) + doughnutChart.clearLayers() + colorLablesStack.removeAllItemViews() + doughnutChart.setWithModel(model, delegateObject, additionalData) + colorLablesStack.setWithModel(model, delegateObject, additionalData) + } + + open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + if model == nil { + let data = try! JSONSerialization.data(withJSONObject: json!) + let decoder = JSONDecoder() + let model = try! decoder.decode(DoughnutChartModel.self, from: data) + setWithModel(model, delegateObject, additionalData as? [String : AnyHashable]) + } else { + setWithModel(model, delegateObject, additionalData as? [String : AnyHashable]) + } + } + +} + +class ColorViewLabelsStack: MoleculeStackView { + + var dougnutChartModel: DoughnutChartModel? + + override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + let previousModel = self.dougnutChartModel + removeAllItemViews() + guard let dougnutChartModel = model as? DoughnutChartModel else { + return + } + var items: [StackItem]? + if previousModel?.sections.count == dougnutChartModel.sections.count { + items = stackItems + } + stackItems = [] + self.model = MoleculeStackModel(molecules: []) + for (index, chartItemModel) in dougnutChartModel.sections.enumerated() { + let colorViewWithLabel = items?[index].view as? ColorViewWithLabel ?? ColorViewWithLabel() + colorViewWithLabel.setWithModel(chartItemModel, delegateObject, additionalData) + addView(colorViewWithLabel, lastItem: index == dougnutChartModel.sections.count - 1) + } + self.dougnutChartModel = dougnutChartModel + restack() + } +} + +class ColorViewWithLabel: View, MVMCoreUIViewConstrainingProtocol { + + var label = Label.commonLabelB2(true) + var colorView = MVMCoreUICommonViewsUtility.commonView() + private var sizeObject = MFStyler.sizeObjectGeneric(forCurrentDevice: 8)! + var heightConstraint: NSLayoutConstraint? + + override func setupView() { + super.setupView() + guard colorView.superview == nil else { + return + } + translatesAutoresizingMaskIntoConstraints = false + addSubview(colorView) + addSubview(label) + + heightConstraint = colorView.heightAnchor.constraint(equalToConstant: sizeObject.getValueBasedOnApplicationWidth()) + heightConstraint?.isActive = true + colorView.widthAnchor.constraint(equalTo: colorView.heightAnchor).isActive = true + colorView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true + colorView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true + + label.leadingAnchor.constraint(equalTo: colorView.trailingAnchor, constant: PaddingOne).isActive = true + label.topAnchor.constraint(equalTo: topAnchor).isActive = true + trailingAnchor.constraint(greaterThanOrEqualTo: label.trailingAnchor).isActive = true + bottomAnchor.constraint(equalTo: label.bottomAnchor).isActive = true + + } + + override func updateView(_ size: CGFloat) { + super.updateView(size) + label.updateView(size) + heightConstraint?.constant = sizeObject.getValueBased(onSize: size) + setNeedsDisplay() + } + + override func reset() { + super.reset() + label.reset() + } + + func setAsMolecule() { + label.setAsMolecule() + } + + override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + super.setWithModel(model, delegateObject, additionalData) + guard let chartItemModel = model as? ChartItemModel else { + return + } + label.setWithModel(chartItemModel.label, delegateObject, additionalData) + colorView.backgroundColor = UIColor.mfGet(forHex: chartItemModel.color) + } + + override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + Label.setUILabel(label, withJSON: json?.optionalDictionaryForKey("label"), delegate: delegateObject, additionalData: additionalData) + colorView.backgroundColor = UIColor.mfGet(forHex: json?.optionalStringForKey("color") ?? "#000000") + } + +} diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index c656ab2f..4b597288 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -68,7 +68,8 @@ @"dropDownListItem": DropDownFilterTableViewCell.class, @"headlineBodyButton": HeadlineBodyButton.class, @"eyebrowHeadlineBodyLink": EyebrowHeadlineBodyLink.class, - @"stackItem": StackItem.class + @"stackItem": StackItem.class, + @"doughnutChart": DoughnutChartView.class } mutableCopy]; }); return mapping; diff --git a/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift b/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift index ac96c44f..651d18a7 100644 --- a/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift +++ b/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift @@ -29,5 +29,6 @@ import Foundation ModelRegistry.register(LabelAttributeUnderlineModel.self) ModelRegistry.register(LabelAttributeStrikeThroughModel.self) ModelRegistry.register(LabelAttributeActionModel.self) + ModelRegistry.register(DoughnutChartModel.self) } }