diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index b1e42d4b..d114d2ae 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -54,7 +54,7 @@ 01E569D3223FFFA500327251 /* ThreeLayerViewController.swift in Headers */ = {isa = PBXBuildFile; fileRef = D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 01EB3684236097C0006832FA /* MoleculeModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB3683236097C0006832FA /* MoleculeModelProtocol.swift */; }; 01EB368F23609801006832FA /* LabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368823609801006832FA /* LabelModel.swift */; }; - 01EB369023609801006832FA /* ListItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368923609801006832FA /* ListItemModel.swift */; }; + 01EB369023609801006832FA /* MoleculeListItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368923609801006832FA /* MoleculeListItemModel.swift */; }; 01EB369223609801006832FA /* MoleculeStackModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368B23609801006832FA /* MoleculeStackModel.swift */; }; 01EB369323609801006832FA /* HeaderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368C23609801006832FA /* HeaderModel.swift */; }; 01EB369423609801006832FA /* HeadlineBodyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368D23609801006832FA /* HeadlineBodyModel.swift */; }; @@ -169,6 +169,7 @@ D260D7B622D68514007E7233 /* MVMCoreUIPagingProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D260D7B522D68509007E7233 /* MVMCoreUIPagingProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; D268C70C2386DFFD007F2C1C /* MoleculeStackItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368A23609801006832FA /* MoleculeStackItemModel.swift */; }; D268C70E238C22D7007F2C1C /* DropDownFilterTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D268C70D238C22D7007F2C1C /* DropDownFilterTableViewCell.swift */; }; + D26C5A6B23F4A40D007AEECE /* ListItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D26C5A6A23F4A40D007AEECE /* ListItemModel.swift */; }; D274CA332236A78900B01B62 /* FooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D274CA322236A78900B01B62 /* FooterView.swift */; }; D2755D7B23689C7500485468 /* TableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2755D7A23689C7500485468 /* TableViewCell.swift */; }; D27CD40E2322EEAF00C1DC07 /* TabsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27CD40D2322EEAF00C1DC07 /* TabsTableViewCell.swift */; }; @@ -311,6 +312,7 @@ D2B1E3E522F37D6A0065F95C /* ImageHeadlineBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B1E3E422F37D6A0065F95C /* ImageHeadlineBody.swift */; }; D2C5001821F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h in Headers */ = {isa = PBXBuildFile; fileRef = D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */; }; + D2C521A923EDE79E00CA2634 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2C521A823EDE79E00CA2634 /* ViewController.swift */; }; D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */; }; D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */; }; D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FADA2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift */; }; @@ -383,7 +385,7 @@ 01C851D223CF9E740021F976 /* LabelToggleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelToggleModel.swift; sourceTree = ""; }; 01EB3683236097C0006832FA /* MoleculeModelProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeModelProtocol.swift; sourceTree = ""; }; 01EB368823609801006832FA /* LabelModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LabelModel.swift; sourceTree = ""; }; - 01EB368923609801006832FA /* ListItemModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListItemModel.swift; sourceTree = ""; }; + 01EB368923609801006832FA /* MoleculeListItemModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeListItemModel.swift; sourceTree = ""; }; 01EB368A23609801006832FA /* MoleculeStackItemModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeStackItemModel.swift; sourceTree = ""; }; 01EB368B23609801006832FA /* MoleculeStackModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeStackModel.swift; sourceTree = ""; }; 01EB368C23609801006832FA /* HeaderModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderModel.swift; sourceTree = ""; }; @@ -488,6 +490,7 @@ D260D7B022D65BDD007E7233 /* MVMCoreUIPageControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIPageControl.m; sourceTree = ""; }; D260D7B522D68509007E7233 /* MVMCoreUIPagingProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIPagingProtocol.h; sourceTree = ""; }; D268C70D238C22D7007F2C1C /* DropDownFilterTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropDownFilterTableViewCell.swift; sourceTree = ""; }; + D26C5A6A23F4A40D007AEECE /* ListItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListItemModel.swift; sourceTree = ""; }; D274CA322236A78900B01B62 /* FooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FooterView.swift; sourceTree = ""; }; D2755D7A23689C7500485468 /* TableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableViewCell.swift; sourceTree = ""; }; D27CD40D2322EEAF00C1DC07 /* TabsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsTableViewCell.swift; sourceTree = ""; }; @@ -645,6 +648,7 @@ D2B1E3E422F37D6A0065F95C /* ImageHeadlineBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageHeadlineBody.swift; sourceTree = ""; }; D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIViewControllerMappingObject.h; sourceTree = ""; }; D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIViewControllerMappingObject.m; sourceTree = ""; }; + D2C521A823EDE79E00CA2634 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scroller.swift; sourceTree = ""; }; D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerTemplate.swift; sourceTree = ""; }; D2E1FADA2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUIDelegateObject.swift; sourceTree = ""; }; @@ -659,7 +663,6 @@ D2E2A99E23E07F8A000B42E6 /* PillButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillButton.swift; sourceTree = ""; }; D2E2A9A023E095AB000B42E6 /* ButtonModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonModelProtocol.swift; sourceTree = ""; }; D2E2A9A223E096B1000B42E6 /* DisableableModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisableableModelProtocol.swift; sourceTree = ""; }; - D2F4DDE52371A4CB00CD28BB /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; D2FB151A23A2B65B00C20E10 /* MoleculeContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeContainer.swift; sourceTree = ""; }; D2FB151C23A40F1500C20E10 /* MoleculeStackItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeStackItem.swift; sourceTree = ""; }; DB06250A2293456500B72DD3 /* LeftRightLabelView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LeftRightLabelView.swift; sourceTree = ""; }; @@ -926,8 +929,8 @@ D22479912316A9EF003FCCF9 /* Items */ = { isa = PBXGroup; children = ( - D2755D7A23689C7500485468 /* TableViewCell.swift */, - 01EB368923609801006832FA /* ListItemModel.swift */, + D26C5A6A23F4A40D007AEECE /* ListItemModel.swift */, + 01EB368923609801006832FA /* MoleculeListItemModel.swift */, 01509D8E2327EC6F00EF99AA /* MoleculeTableViewCell.swift */, 012A88C1238D7BCA00FE3DA1 /* CarouselItemModel.swift */, D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */, @@ -1131,7 +1134,7 @@ D29DF2CD21E7C104003B2FB9 /* MFLoadingViewController.m */, D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */, D2E1FADE2268B8E700AEFD8C /* ThreeLayerTableViewController.swift */, - D2F4DDE52371A4CB00CD28BB /* ViewController.swift */, + D2C521A823EDE79E00CA2634 /* ViewController.swift */, ); path = BaseControllers; sourceTree = ""; @@ -1429,6 +1432,7 @@ D2B18B7E2360913400A9AEDC /* Control.swift */, D2B18B802360945C00A9AEDC /* View.swift */, 0AE14F63238315D2005417F8 /* TextField.swift */, + D2755D7A23689C7500485468 /* TableViewCell.swift */, 0A5D59C323AD488600EFD9E9 /* Protocols */, ); path = BaseClasses; @@ -1681,7 +1685,7 @@ 012A88EC238F084D00FE3DA1 /* FooterModel.swift in Sources */, D2A514672213885800345BFB /* HeaderView.swift in Sources */, D29E28D823D21AB800ACEA85 /* StringAndMoleculeView.swift in Sources */, - 01EB369023609801006832FA /* ListItemModel.swift in Sources */, + 01EB369023609801006832FA /* MoleculeListItemModel.swift in Sources */, D28A838323CCBD3F00DFE4FC /* CircleProgressModel.swift in Sources */, D268C70C2386DFFD007F2C1C /* MoleculeStackItemModel.swift in Sources */, DBEFFA04225A829700230692 /* Label.swift in Sources */, @@ -1775,6 +1779,7 @@ D29DF11D21E684A9003B2FB9 /* MVMCoreUISplitViewController.m in Sources */, 0198F79F225679880066C936 /* FormValidationProtocol.swift in Sources */, D243859923A16B1800332775 /* Container.swift in Sources */, + D2C521A923EDE79E00CA2634 /* ViewController.swift in Sources */, D260105B23D0BB7100764D80 /* StackModelProtocol.swift in Sources */, D29DF29821E7ADB8003B2FB9 /* MFScrollingViewController.m in Sources */, D28A839323CE828900DFE4FC /* HeadlineBodyCaretLinkImageModel.swift in Sources */, @@ -1790,6 +1795,7 @@ D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */, D2B1E3E522F37D6A0065F95C /* ImageHeadlineBody.swift in Sources */, 0A21DB94235E24ED00C160A2 /* DigitEntryField.swift in Sources */, + D26C5A6B23F4A40D007AEECE /* ListItemModel.swift in Sources */, 0A21DB8D235E06EF00C160A2 /* MFDigitTextField.m in Sources */, 94AF4A4323E9D19E00676048 /* MFCaretView.m in Sources */, 943784F6236B77BB006A1E82 /* GraphViewAnimationHandler.swift in Sources */, diff --git a/MVMCoreUI/Molecules/Items/TableViewCell.swift b/MVMCoreUI/BaseClasses/TableViewCell.swift similarity index 96% rename from MVMCoreUI/Molecules/Items/TableViewCell.swift rename to MVMCoreUI/BaseClasses/TableViewCell.swift index cd8a3cdf..fe06a05a 100644 --- a/MVMCoreUI/Molecules/Items/TableViewCell.swift +++ b/MVMCoreUI/BaseClasses/TableViewCell.swift @@ -28,6 +28,8 @@ import UIKit private var heroAccessoryCenter: CGPoint? + private var initialSetupPerformed = false + // MARK: - Styling open func style(with styleString: String?) { guard let styleString = styleString else { @@ -102,12 +104,19 @@ import UIKit // MARK: - Inits public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) - setupView() + initialSetup() } public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - setupView() + initialSetup() + } + + public func initialSetup() { + if !initialSetupPerformed { + initialSetupPerformed = true + setupView() + } } // MARK: - MFViewProtocol @@ -151,10 +160,6 @@ import UIKit self.listItemModel = model style(with: model.style) - if let backgroundColor = model.backgroundColor { - self.backgroundColor = backgroundColor.uiColor - } - // Add the caret if there is an action and it's not declared hidden. if !customAccessoryView { if let _ = model.action, !(model.hideArrow ?? false) { @@ -169,11 +174,15 @@ import UIKit addSeparatorsIfNeeded() bottomSeparatorView?.setWithModel(separator, nil, nil) } + + if let moleculeModel = model as? MoleculeModelProtocol, + let backgroundColor = moleculeModel.backgroundColor { + self.backgroundColor = backgroundColor.uiColor + } } open func reset() { molecule?.reset?() - styleStandard() backgroundColor = .white } diff --git a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift index 3176df92..ae3d2fac 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift @@ -166,6 +166,8 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { } // This extra view is needed because of the wonkiness of apple's table header. Things breaks if using autolayout. + headerView.setNeedsLayout() + headerView.layoutIfNeeded() MVMCoreUIUtility.sizeView(toFit: headerView) let tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: MVMCoreUIUtility.getWidth(), height: headerView.frame.height)) tableHeaderView.addSubview(headerView) diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift new file mode 100644 index 00000000..1bb06324 --- /dev/null +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -0,0 +1,82 @@ +// +// ViewController.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 11/5/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +@objcMembers open class ViewController: UIViewController, MVMCoreViewControllerProtocol { + public var pageType: String? + public var loadObject: MVMCoreLoadObject? + public var pageModel: PageModelProtocol? + + // MARK: Response handling + public func shouldFinishProcessingLoad(_ loadObject: MVMCoreLoadObject, error: AutoreleasingUnsafeMutablePointer) -> Bool { + pageType = loadObject.pageType + self.loadObject = loadObject + + // Parse the model for the page. + do { + try parsePageJSON() + } catch let parsingError { + // Log all parsing errors and fail load. + if let errorObject = MVMCoreErrorObject.createErrorObject(for: parsingError, location: MVMCoreLoadHandler.sharedGlobal()?.errorLocation(forRequest: loadObject)) { + errorObject.messageToDisplay = MVMCoreGetterUtility.hardcodedString(withKey: HardcodedErrorUnableToProcess) + error.pointee = errorObject + } + return false + } + + // Verifies all modules needed are loaded. + return MFViewController.verifyRequiredModulesLoaded(for: loadObject, error: error) + } + + @objc func parsePageJSON() throws { + } + + public class func verifyRequiredModulesLoaded(for loadObject: MVMCoreLoadObject?, error: inout MVMCoreErrorObject?) -> Bool { + guard let pageType = loadObject?.pageType, var modulesRequired = MVMCoreUIViewControllerMappingObject.shared()?.modulesRequired(forPageType: pageType) else { return true } + + guard let loadedModules = loadObject?.modulesJSON else { return false } + + for case let key as String in Array(loadedModules.keys) { + guard modulesRequired.count > 0 else { break } + if let index = modulesRequired.firstIndex(where: {($0 as? String) == key}) { + modulesRequired.remove(at: index) + } + } + + guard modulesRequired.count == 0 else { + if error != nil { + error = MVMCoreErrorObject(title: nil, message: MVMCoreGetterUtility.hardcodedString(withKey: HardcodedErrorCritical), messageToLog: modulesRequired.description, code: ErrorCode.requiredModuleNotPresent.rawValue, domain: ErrorDomainNative, location: MVMCoreLoadHandler.sharedGlobal()?.errorLocation(forRequest: loadObject!)) + } + return false + } + return true + } + + open func setNavigationItem() { + navigationItem.title = pageModel?.screenHeading + navigationItem.accessibilityLabel = pageModel?.screenHeading + } + + open func newDataBuildScreen() { + // TODO atomize the navigation item + setNavigationItem() + } + + open func initialLoad() { + } + + open func updateViews() { + } + + override open func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + } +} diff --git a/MVMCoreUI/Categories/NSLayoutConstraintExtension.swift b/MVMCoreUI/Categories/NSLayoutConstraintExtension.swift index bf6c8f65..4057a88c 100644 --- a/MVMCoreUI/Categories/NSLayoutConstraintExtension.swift +++ b/MVMCoreUI/Categories/NSLayoutConstraintExtension.swift @@ -9,36 +9,52 @@ import Foundation public extension NSLayoutConstraint { - static func pinSubviewsCenter(leftView: UIView, rightView: UIView) { - guard let superView = leftView.superview else { - return + + /// Pins the views vertically in the super view, allowing the super to expand depending on the tallest view. Shorter views are aligned center. + static func pinViewsVerticalExpandableAlignCenter(_ views: [UIView]) { + for view in views { + guard let superView = view.superview else { + return + } + view.centerYAnchor.constraint(equalTo: superView.centerYAnchor).isActive = true + view.topAnchor.constraint(greaterThanOrEqualTo: superView.layoutMarginsGuide.topAnchor).isActive = true + superView.layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: view.bottomAnchor).isActive = true + + var constraint = view.topAnchor.constraint(equalTo: superView.layoutMarginsGuide.topAnchor) + constraint.priority = .defaultLow + constraint.isActive = true + + constraint = superView.layoutMarginsGuide.bottomAnchor.constraint(equalTo: view.bottomAnchor) + constraint.priority = .defaultLow + constraint.isActive = true } - leftView.centerYAnchor.constraint(equalTo: superView.centerYAnchor).isActive = true - leftView.leftAnchor.constraint(equalTo: superView.layoutMarginsGuide.leftAnchor).isActive = true - leftView.topAnchor.constraint(greaterThanOrEqualTo: superView.layoutMarginsGuide.topAnchor).isActive = true - superView.layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: leftView.bottomAnchor).isActive = true + } + + /// Pins the views vertically in the super view, allowing the super to expand depending on the tallest view. Shorter views are aligned top. + static func pinViewsVerticalExpandableAlignTop(_ views: [UIView]) { + for view in views { + guard let superView = view.superview else { + return + } + view.topAnchor.constraint(equalTo: superView.layoutMarginsGuide.topAnchor).isActive = true + superView.layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: view.bottomAnchor).isActive = true - var constraint = leftView.topAnchor.constraint(equalTo: superView.layoutMarginsGuide.topAnchor) - constraint.priority = .defaultLow - constraint.isActive = true - - constraint = superView.layoutMarginsGuide.bottomAnchor.constraint(equalTo: leftView.bottomAnchor) - constraint.priority = .defaultLow - constraint.isActive = true - - rightView.leftAnchor.constraint(greaterThanOrEqualTo: leftView.rightAnchor, constant: 16).isActive = true - - rightView.centerYAnchor.constraint(equalTo: superView.centerYAnchor).isActive = true - superView.layoutMarginsGuide.rightAnchor.constraint(equalTo: rightView.rightAnchor).isActive = true - rightView.topAnchor.constraint(greaterThanOrEqualTo: superView.layoutMarginsGuide.topAnchor).isActive = true - superView.layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: rightView.bottomAnchor).isActive = true - - constraint = rightView.topAnchor.constraint(equalTo: superView.layoutMarginsGuide.topAnchor) - constraint.priority = .defaultLow - constraint.isActive = true - - constraint = superView.layoutMarginsGuide.bottomAnchor.constraint(equalTo: rightView.bottomAnchor) - constraint.priority = .defaultLow - constraint.isActive = true + let constraint = superView.layoutMarginsGuide.bottomAnchor.constraint(equalTo: view.bottomAnchor) + constraint.priority = .defaultLow + constraint.isActive = true + } + } + + /// Pins a view to the left and a view to the right, flexible space in between. The super can expand depending on the taller view. Shorter views are aligned top if alignTop true, else aligned center. + static func pinViews(leftView: UIView, rightView: UIView, alignTop: Bool) { + guard let superView = leftView.superview else { return } + if alignTop { + pinViewsVerticalExpandableAlignTop([leftView, rightView]) + } else { + pinViewsVerticalExpandableAlignCenter([leftView, rightView]) + } + leftView.leadingAnchor.constraint(equalTo: superView.layoutMarginsGuide.leadingAnchor).isActive = true + superView.layoutMarginsGuide.trailingAnchor.constraint(equalTo: rightView.trailingAnchor).isActive = true + rightView.leftAnchor.constraint(greaterThanOrEqualTo: leftView.rightAnchor, constant: PaddingHorizontalBetweenRelatedItems).isActive = true } } diff --git a/MVMCoreUI/Containers/Views/Container/ContainerModel.swift b/MVMCoreUI/Containers/Views/Container/ContainerModel.swift index 1b721183..cdc6d743 100644 --- a/MVMCoreUI/Containers/Views/Container/ContainerModel.swift +++ b/MVMCoreUI/Containers/Views/Container/ContainerModel.swift @@ -48,7 +48,8 @@ public class ContainerModel: ContainerModelProtocol, Codable { try container.encodeIfPresent(ContainerHelper.getAlignmentString(for: horizontalAlignment), forKey: .horizontalAlignment) try container.encodeIfPresent(useHorizontalMargins, forKey: .useHorizontalMargins) try container.encodeIfPresent(useVerticalMargins, forKey: .useVerticalMargins) - try container.encodeIfPresent(topMarginPadding, forKey: .topMarginPadding) - try container.encodeIfPresent(bottomMarginPadding, forKey: .bottomMarginPadding) + // TODO: can add this back once we have type erasures. + //try container.encodeIfPresent(topMarginPadding, forKey: .topMarginPadding) + //try container.encodeIfPresent(bottomMarginPadding, forKey: .bottomMarginPadding) } } diff --git a/MVMCoreUI/Models/ModelProtocols/ListItemModelProtocol.swift b/MVMCoreUI/Models/ModelProtocols/ListItemModelProtocol.swift index 020c3cbe..5d0fee08 100644 --- a/MVMCoreUI/Models/ModelProtocols/ListItemModelProtocol.swift +++ b/MVMCoreUI/Models/ModelProtocols/ListItemModelProtocol.swift @@ -9,7 +9,7 @@ import Foundation -public protocol ListItemModelProtocol: ContainerModelProtocol, MoleculeModelProtocol { +public protocol ListItemModelProtocol: ContainerModelProtocol { var line: LineModel? { get set } var action: ActionModelProtocol? { get set } var hideArrow: Bool? { get set } diff --git a/MVMCoreUI/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaret.swift b/MVMCoreUI/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaret.swift index 62a19d01..9f0e2deb 100644 --- a/MVMCoreUI/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaret.swift +++ b/MVMCoreUI/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaret.swift @@ -29,9 +29,6 @@ import UIKit override open func setupView() { super.setupView() - guard leftImage.superview == nil else { - return - } stack.translatesAutoresizingMaskIntoConstraints = false stack.stackItems = [StackItem(andContain: leftImage),StackItem(andContain: leftLabel),StackItem(andContain: rightLabel)] contentView.addSubview(stack) diff --git a/MVMCoreUI/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretModel.swift b/MVMCoreUI/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretModel.swift index cac928d3..bccf5320 100644 --- a/MVMCoreUI/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretModel.swift +++ b/MVMCoreUI/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretModel.swift @@ -8,25 +8,14 @@ import Foundation -public class ListLeftVariableIconWithRightCaretModel: ContainerModel, ListItemModelProtocol { - - public var line: LineModel? - public var style: String? = "standard" - public var hideArrow: Bool? = false - public var backgroundColor: Color? - public var action: ActionModelProtocol? +public class ListLeftVariableIconWithRightCaretModel: ListItemModel, MoleculeModelProtocol { public static var identifier: String = "listLVImg" public var image: ImageViewModel public var leftLabel: LabelModel public var rightLabel: LabelModel - func setDefaults() { - if useHorizontalMargins == nil { - useHorizontalMargins = true - } - if useVerticalMargins == nil { - useVerticalMargins = true - } + override public func setDefaults() { + super.setDefaults() if image.height == nil { image.height = 30.0 } @@ -37,7 +26,6 @@ public class ListLeftVariableIconWithRightCaretModel: ContainerModel, ListItemMo self.leftLabel = leftLabel self.rightLabel = rightLabel super.init() - setDefaults() } private enum CodingKeys: String, CodingKey { @@ -45,8 +33,6 @@ public class ListLeftVariableIconWithRightCaretModel: ContainerModel, ListItemMo case leftLabel case rightLabel case image - case action - case backgroundColor } required public init(from decoder: Decoder) throws { @@ -54,10 +40,7 @@ public class ListLeftVariableIconWithRightCaretModel: ContainerModel, ListItemMo leftLabel = try typeContainer.decode(LabelModel.self, forKey: .leftLabel) rightLabel = try typeContainer.decode(LabelModel.self, forKey: .rightLabel) image = try typeContainer.decode(ImageViewModel.self, forKey: .image) - action = try typeContainer.decodeModelIfPresent(codingKey: .action, typeCodingKey: ActionCodingKey.actionType) - backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) try super.init(from: decoder) - setDefaults() } public override func encode(to encoder: Encoder) throws { @@ -67,8 +50,6 @@ public class ListLeftVariableIconWithRightCaretModel: ContainerModel, ListItemMo try container.encode(leftLabel, forKey: .leftLabel) try container.encode(rightLabel, forKey: .rightLabel) try container.encode(image, forKey: .image) - try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) - try container.encodeModelIfPresent(action, forKey: .action) } } diff --git a/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnPlanDataDivider.swift b/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnPlanDataDivider.swift index e685ce6b..19774110 100644 --- a/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnPlanDataDivider.swift +++ b/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnPlanDataDivider.swift @@ -23,9 +23,7 @@ import Foundation open override func setupView() { super.setupView() - guard leftHeadlineBody.superview == nil else { - return - } + //using stackItems to align the three headlineBody stack.translatesAutoresizingMaskIntoConstraints = false stack.stackItems = [StackItem(andContain: leftHeadlineBody),StackItem(andContain: centerHeadLineBody),StackItem(andContain: rightHeadLineBody)] diff --git a/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnPlanDataDividerModel.swift b/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnPlanDataDividerModel.swift index 47e97a5a..fd946eb0 100644 --- a/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnPlanDataDividerModel.swift +++ b/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnPlanDataDividerModel.swift @@ -8,11 +8,7 @@ import UIKit -public class ListThreeColumnPlanDataDividerModel: ContainerModel, ListItemModelProtocol { - public var hideArrow: Bool? - public var style: String? = "tallDivider" - public var line: LineModel? - public var backgroundColor: Color? +public class ListThreeColumnPlanDataDividerModel: ListItemModel, MoleculeModelProtocol { public static var identifier: String = "list3CHBDiv" public var leftHeadlineBody: HeadlineBodyModel public var centerHeadlineBody: HeadlineBodyModel @@ -27,13 +23,9 @@ public class ListThreeColumnPlanDataDividerModel: ContainerModel, ListItemModelP } /// Defaults to set - func setDefaults() { - if useHorizontalMargins == nil { - useHorizontalMargins = true - } - if useVerticalMargins == nil { - useVerticalMargins = true - } + override public func setDefaults() { + super.setDefaults() + style = "tallDivider" } private enum CodingKeys: String, CodingKey { @@ -41,7 +33,6 @@ public class ListThreeColumnPlanDataDividerModel: ContainerModel, ListItemModelP case leftHeadlineBody case centerHeadlineBody case rightHeadlineBody - case backgroundColor } required public init(from decoder: Decoder) throws { @@ -49,9 +40,7 @@ public class ListThreeColumnPlanDataDividerModel: ContainerModel, ListItemModelP leftHeadlineBody = try typeContainer.decode(HeadlineBodyModel.self, forKey: .leftHeadlineBody) centerHeadlineBody = try typeContainer.decode(HeadlineBodyModel.self, forKey: .centerHeadlineBody) rightHeadlineBody = try typeContainer.decode(HeadlineBodyModel.self, forKey: .rightHeadlineBody) - backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) try super.init(from: decoder) - setDefaults() } public override func encode(to encoder: Encoder) throws { @@ -61,7 +50,6 @@ public class ListThreeColumnPlanDataDividerModel: ContainerModel, ListItemModelP try container.encode(leftHeadlineBody, forKey: .leftHeadlineBody) try container.encode(centerHeadlineBody, forKey: .centerHeadlineBody) try container.encode(rightHeadlineBody, forKey: .rightHeadlineBody) - try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) } } diff --git a/MVMCoreUI/Molecules/HorizontalCombinationViews/ImageHeadlineBody.swift b/MVMCoreUI/Molecules/HorizontalCombinationViews/ImageHeadlineBody.swift index 089352c7..840f4763 100644 --- a/MVMCoreUI/Molecules/HorizontalCombinationViews/ImageHeadlineBody.swift +++ b/MVMCoreUI/Molecules/HorizontalCombinationViews/ImageHeadlineBody.swift @@ -10,13 +10,14 @@ import UIKit @objcMembers open class ImageHeadlineBody: View { let headlineBody = HeadlineBody(frame: .zero) - let imageView = MFLoadImageView() + let imageView = MFLoadImageView(pinnedEdges: .all) var constraintBetweenImageLabelsConstant: CGFloat = 16 var constraintBetweenImageLabels: NSLayoutConstraint? // MARK: - MFViewProtocol open override func setupView() { + super.setupView() guard subviews.count == 0 else { return } @@ -26,23 +27,9 @@ import UIKit addSubview(headlineBody) addSubview(imageView) - headlineBody.topAnchor.constraint(equalTo: topAnchor).isActive = true + NSLayoutConstraint.pinViewsVerticalExpandableAlignCenter([imageView, headlineBody]) rightAnchor.constraint(equalTo: headlineBody.rightAnchor).isActive = true - bottomAnchor.constraint(greaterThanOrEqualTo: headlineBody.bottomAnchor).isActive = true - var constraint = bottomAnchor.constraint(equalTo: headlineBody.bottomAnchor) - constraint.priority = .defaultLow - constraint.isActive = true - - imageView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true imageView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true - imageView.topAnchor.constraint(greaterThanOrEqualTo: topAnchor).isActive = true - bottomAnchor.constraint(greaterThanOrEqualTo: imageView.bottomAnchor).isActive = true - constraint = bottomAnchor.constraint(equalTo: imageView.bottomAnchor) - constraint.priority = UILayoutPriority(rawValue: 200) - constraint.isActive = true - constraint = imageView.topAnchor.constraint(equalTo: topAnchor) - constraint.priority = UILayoutPriority(rawValue: 200) - constraint.isActive = true constraintBetweenImageLabels = headlineBody.leadingAnchor.constraint(equalTo: imageView.trailingAnchor, constant: constraintBetweenImageLabelsConstant) constraintBetweenImageLabels?.isActive = true diff --git a/MVMCoreUI/Molecules/Items/AccordionListItemModel.swift b/MVMCoreUI/Molecules/Items/AccordionListItemModel.swift index 0e2fa531..60192c2d 100644 --- a/MVMCoreUI/Molecules/Items/AccordionListItemModel.swift +++ b/MVMCoreUI/Molecules/Items/AccordionListItemModel.swift @@ -8,28 +8,31 @@ import UIKit -class AccordionListItemModel: MoleculeContainerModel, ListItemModelProtocol { - public static var identifier: String = "accordionListItem" - public var molecules: [ListItemModelProtocol] - public var backgroundColor: Color? +class AccordionListItemModel: MoleculeListItemModel { + override public class var identifier: String { + return "accordionListItem" + } + public var molecules: [ListItemModelProtocol & MoleculeModelProtocol] public var hideLineWhenExpanded: Bool = false - public var hideArrow: Bool? = true - public var line: LineModel? private enum CodingKeys: String, CodingKey { case moleculeName case molecules - case backgroundColor + case molecule case hideLineWhenExpanded - case hideArrow - case line + } + + public override func setDefaults() { + super.setDefaults() + hideArrow = true } required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - molecules = try typeContainer.decodeMolecules(codingKey: .molecules) as! [ListItemModelProtocol] - backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) - line = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line) + guard let molecules = try typeContainer.decodeMolecules(codingKey: .molecules) as? [ListItemModelProtocol & MoleculeModelProtocol] else { + throw DecodingError.typeMismatch([ListItemModelProtocol & MoleculeModelProtocol].self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Casting failed")) + } + self.molecules = molecules if let hideLine = try typeContainer.decodeIfPresent(Bool.self, forKey: .hideLineWhenExpanded) { hideLineWhenExpanded = hideLine } @@ -41,8 +44,6 @@ class AccordionListItemModel: MoleculeContainerModel, ListItemModelProtocol { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(moleculeName, forKey: .moleculeName) try container.encodeModels(molecules, forKey: .molecules) - try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) try container.encodeIfPresent(hideLineWhenExpanded, forKey: .hideLineWhenExpanded) - try container.encodeIfPresent(line, forKey: .line) } } diff --git a/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift index db4e322e..714c7dd9 100644 --- a/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift @@ -9,7 +9,9 @@ import UIKit @objcMembers public class AccordionMoleculeTableViewCell: MoleculeTableViewCell { - var accordionListItemModel: AccordionListItemModel? + var accordionListItemModel: AccordionListItemModel? { + return listItemModel as? AccordionListItemModel + } let accordionButton = createAccordionButton() static func createAccordionButton() -> MFCustomButton { @@ -30,10 +32,14 @@ import UIKit override public func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { accordionButton.isSelected = !accordionButton.isSelected accordionButton.setTitle(accordionButton.isSelected ? "-" : "+", for: .normal) - guard let molecules = accordionListItemModel?.molecules else { + guard let model = accordionListItemModel else { return } + guard let json = model.toJSON(), + let molecules = json.optionalArrayForKey("molecules") as? [[AnyHashable: Any]] + else { return } + if accordionButton.isSelected { delegateObject?.moleculeDelegate?.addMolecules(molecules, sender: self, animation: .automatic) } else { diff --git a/MVMCoreUI/Molecules/Items/DropDownFilterTableViewCell.swift b/MVMCoreUI/Molecules/Items/DropDownFilterTableViewCell.swift index 081da875..164bd2c3 100644 --- a/MVMCoreUI/Molecules/Items/DropDownFilterTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/DropDownFilterTableViewCell.swift @@ -24,9 +24,7 @@ import UIKit override public func setupView() { super.setupView() - - guard dropDown.superview == nil else { return } - + addMolecule(dropDown) dropDown.observeDropdownChange = { [weak self] oldValue, newValue in diff --git a/MVMCoreUI/Molecules/Items/DropDownListItemModel.swift b/MVMCoreUI/Molecules/Items/DropDownListItemModel.swift index 35f69b51..b623f20e 100644 --- a/MVMCoreUI/Molecules/Items/DropDownListItemModel.swift +++ b/MVMCoreUI/Molecules/Items/DropDownListItemModel.swift @@ -8,43 +8,31 @@ import Foundation -@objcMembers public class DropDownListItemModel: ContainerModel, ListItemModelProtocol { +@objcMembers public class DropDownListItemModel: ListItemModel, MoleculeModelProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- public static var identifier: String = "dropDownListItem" - public var molecules: [[ListItemModelProtocol]] + public var molecules: [[ListItemModelProtocol & MoleculeModelProtocol]] public var dropDown: ItemDropdownEntryFieldModel - public var backgroundColor: Color? - public var line: LineModel? = LineModel(type: .none) - public var hideArrow: Bool? = true /// Defaults to set - func setDefaults() { - if useHorizontalMargins == nil { - useHorizontalMargins = true - } - if useVerticalMargins == nil { - useVerticalMargins = true - } - if topMarginPadding == nil { - topMarginPadding = 24 - } - if bottomMarginPadding == nil { - bottomMarginPadding = 0 - } + public override func setDefaults() { + super.setDefaults() + hideArrow = true + line = LineModel(type: .none) + style = "sectionFooter" } //-------------------------------------------------- // MARK: - Initializer //-------------------------------------------------- - public init(molecules: [[ListItemModelProtocol]], dropDown: ItemDropdownEntryFieldModel) { + public init(molecules: [[ListItemModelProtocol & MoleculeModelProtocol]], dropDown: ItemDropdownEntryFieldModel) { self.molecules = molecules self.dropDown = dropDown super.init() - setDefaults() } //-------------------------------------------------- @@ -55,8 +43,6 @@ import Foundation case moleculeName case molecules case dropDown - case line - case backgroundColor } //-------------------------------------------------- @@ -65,16 +51,9 @@ import Foundation required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - molecules = try typeContainer.decodeMolecules2D(codingKey: .molecules) as? [[ListItemModelProtocol]] ?? [[]] + molecules = try typeContainer.decodeMolecules2D(codingKey: .molecules) as? [[ListItemModelProtocol & MoleculeModelProtocol]] ?? [[]] dropDown = try typeContainer.decode(ItemDropdownEntryFieldModel.self, forKey: .dropDown) - - if let lineModel = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line) { - line = lineModel - } - - backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) try super.init(from: decoder) - setDefaults() } public override func encode(to encoder: Encoder) throws { @@ -83,7 +62,5 @@ import Foundation try container.encode(moleculeName, forKey: .moleculeName) try container.encodeModels2D(molecules, forKey: .molecules) try container.encode(dropDown, forKey: .dropDown) - try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) - try container.encodeIfPresent(line, forKey: .line) } } diff --git a/MVMCoreUI/Molecules/Items/ListItemModel.swift b/MVMCoreUI/Molecules/Items/ListItemModel.swift index ffb0eb35..973a487a 100644 --- a/MVMCoreUI/Molecules/Items/ListItemModel.swift +++ b/MVMCoreUI/Molecules/Items/ListItemModel.swift @@ -1,25 +1,22 @@ // -// ListItem.swift +// BaseListItemModel.swift // MVMCoreUI // -// Created by Suresh, Kamlesh on 10/3/19. -// Copyright © 2019 Suresh, Kamlesh. All rights reserved. +// Created by Scott Pfeil on 2/12/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. // +// A base class that has common list item boilerplate model stuffs. import Foundation -import MVMCore -@objcMembers public class ListItemModel: MoleculeContainerModel, ListItemModelProtocol { - - public static var identifier: String = "listItem" +@objcMembers public class ListItemModel: ContainerModel, ListItemModelProtocol { public var backgroundColor: Color? public var action: ActionModelProtocol? public var hideArrow: Bool? public var line: LineModel? - public var style: String? = "standard" + public var style: String? private enum CodingKeys: String, CodingKey { - case moleculeName case backgroundColor case action case hideArrow @@ -28,23 +25,20 @@ import MVMCore } /// Defaults to set - func setDefaults() { + public func setDefaults() { if useHorizontalMargins == nil { useHorizontalMargins = true } if useVerticalMargins == nil { useVerticalMargins = true } - if topMarginPadding == nil { - topMarginPadding = 24 - } - if bottomMarginPadding == nil { - bottomMarginPadding = 24 + if style == nil { + style = "standard" } } - public override init(with moleculeModel: MoleculeModelProtocol) { - super.init(with: moleculeModel) + public override init() { + super.init() setDefaults() } @@ -54,9 +48,7 @@ import MVMCore action = try typeContainer.decodeModelIfPresent(codingKey: .action, typeCodingKey: ActionCodingKey.actionType) hideArrow = try typeContainer.decodeIfPresent(Bool.self, forKey: .hideArrow) line = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line) - if let style = try typeContainer.decodeIfPresent(String.self, forKey: .style) { - self.style = style - } + style = try typeContainer.decodeIfPresent(String.self, forKey: .style) try super.init(from: decoder) setDefaults() } @@ -64,7 +56,6 @@ import MVMCore public override func encode(to encoder: Encoder) throws { try super.encode(to: encoder) var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(moleculeName, forKey: .moleculeName) try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) try container.encodeModelIfPresent(action, forKey: .action) try container.encodeIfPresent(hideArrow, forKey: .hideArrow) diff --git a/MVMCoreUI/Molecules/Items/MoleculeListItemModel.swift b/MVMCoreUI/Molecules/Items/MoleculeListItemModel.swift new file mode 100644 index 00000000..499669c6 --- /dev/null +++ b/MVMCoreUI/Molecules/Items/MoleculeListItemModel.swift @@ -0,0 +1,41 @@ +// +// ListItem.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 10/3/19. +// Copyright © 2019 Suresh, Kamlesh. All rights reserved. +// + +import Foundation +import MVMCore + +@objcMembers public class MoleculeListItemModel: ListItemModel, MoleculeModelProtocol { + public class var identifier: String { + return "listItem" + } + public var molecule: MoleculeModelProtocol + + private enum CodingKeys: String, CodingKey { + case moleculeName + case molecule + } + + public init(with moleculeModel: MoleculeModelProtocol) { + molecule = moleculeModel + super.init() + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + molecule = try typeContainer.decodeMolecule(codingKey: .molecule) + try super.init(from: decoder) + } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encodeModel(molecule, forKey: .molecule) + } +} + diff --git a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift index 9f27a918..0416ce8e 100644 --- a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift @@ -16,7 +16,7 @@ import UIKit public override func setWithModel(_ model: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.setWithModel(model, delegateObject, additionalData) - guard let model = model as? ListItemModel else { return } + guard let model = model as? MoleculeListItemModel else { return } if molecule != nil { (molecule as? ModelMoleculeViewProtocol)?.setWithModel(model.molecule, delegateObject, additionalData) @@ -29,7 +29,7 @@ import UIKit } public override class func nameForReuse(_ model: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?) -> String? { - guard let moleculeModel = (model as? ListItemModel)?.molecule else { return "\(self)<>" } + guard let moleculeModel = (model as? MoleculeListItemModel)?.molecule else { return "\(self)<>" } let className = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(moleculeModel) as? ModelMoleculeViewProtocol.Type let moleculeName = className?.nameForReuse(moleculeModel, delegateObject) ?? moleculeModel.moleculeName ?? "" diff --git a/MVMCoreUI/Molecules/Items/TabsListItemModel.swift b/MVMCoreUI/Molecules/Items/TabsListItemModel.swift index 0158774a..c89ee1a0 100644 --- a/MVMCoreUI/Molecules/Items/TabsListItemModel.swift +++ b/MVMCoreUI/Molecules/Items/TabsListItemModel.swift @@ -8,39 +8,36 @@ import UIKit -public class TabsListItemModel: ContainerModel, ListItemModelProtocol { +public class TabsListItemModel: ListItemModel, MoleculeModelProtocol { public static var identifier: String = "tabsListItem" var tabs: TabsModel - var molecules: [[ListItemModelProtocol]] - - public var backgroundColor: Color? - public var hideArrow: Bool? = true - public var line: LineModel? = LineModel(type: .standard) + var molecules: [[ListItemModelProtocol & MoleculeModelProtocol]] private enum CodingKeys: String, CodingKey { case moleculeName case tabs case molecules - case backgroundColor - case line } - public init(with tabs: TabsModel, molecules: [[ListItemModelProtocol]]) { + public override func setDefaults() { + super.setDefaults() + hideArrow = true + action = nil + style = nil + topMarginPadding = 8 + bottomMarginPadding = 0 + } + + public init(with tabs: TabsModel, molecules: [[ListItemModelProtocol & MoleculeModelProtocol]]) { self.tabs = tabs self.molecules = molecules super.init() - self.topMarginPadding = 8 - self.bottomMarginPadding = 0 } required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) tabs = try typeContainer.decode(TabsModel.self, forKey: .tabs) - molecules = try typeContainer.decodeMolecules2D(codingKey: .molecules) as! [[ListItemModelProtocol]] - backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) - if let lineModel = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line) { - line = lineModel - } + molecules = try typeContainer.decodeMolecules2D(codingKey: .molecules) as! [[ListItemModelProtocol & MoleculeModelProtocol]] try super.init(from: decoder) } @@ -50,7 +47,5 @@ public class TabsListItemModel: ContainerModel, ListItemModelProtocol { try container.encode(moleculeName, forKey: .moleculeName) try container.encode(tabs, forKey: .tabs) try container.encodeModels2D(molecules, forKey: .molecules) - try container.encode(backgroundColor, forKey: .backgroundColor) - try container.encodeIfPresent(line, forKey: .line) } } diff --git a/MVMCoreUI/Molecules/Items/TabsTableViewCell.swift b/MVMCoreUI/Molecules/Items/TabsTableViewCell.swift index cf09eb51..8a971221 100644 --- a/MVMCoreUI/Molecules/Items/TabsTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/TabsTableViewCell.swift @@ -9,7 +9,9 @@ import UIKit @objcMembers public class TabsTableViewCell: TableViewCell { - var tabsListItemModel: TabsListItemModel? + var tabsListItemModel: TabsListItemModel? { + return listItemModel as? TabsListItemModel + } let tabs = TopTabbar(frame: .zero) var delegateObject: MVMCoreUIDelegateObject? var previousTabIndex = 0 @@ -17,11 +19,7 @@ import UIKit // MARK: - MFViewProtocol override public func setupView() { super.setupView() - guard tabs.superview == nil else { - return - } tabs.paddingBeforeFirstTab = false - tabs.translatesAutoresizingMaskIntoConstraints = false tabs.delegate = self tabs.datasource = self @@ -48,11 +46,18 @@ import UIKit super.reset() tabs.reset() } + + public override class func estimatedHeight(forRow molecule: MoleculeModelProtocol?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { + return 46 + } } extension TabsTableViewCell: TopTabbarDelegate { public func shouldSelectItem(at index: Int, topTabbar: TopTabbar) -> Bool { - if let molecules = tabsListItemModel?.molecules[topTabbar.selectedIndex] { + if let model = tabsListItemModel, + let json = model.toJSON(), + let json2d = json.optionalArrayForKey("molecules") as? [[[AnyHashable: Any]]] { + let molecules = json2d[topTabbar.selectedIndex] delegateObject?.moleculeDelegate?.removeMolecules(molecules, sender: self, animation: index < tabs.selectedIndex ? .right : .left) } previousTabIndex = tabs.selectedIndex @@ -60,7 +65,10 @@ extension TabsTableViewCell: TopTabbarDelegate { } public func topTabbar(_ topTabbar: TopTabbar, didSelectItemAt index: Int) { - if let molecules = tabsListItemModel?.molecules[index] { + if let model = tabsListItemModel, + let json = model.toJSON(), + let json2d = json.optionalArrayForKey("molecules") as? [[[AnyHashable: Any]]] { + let molecules = json2d[index] delegateObject?.moleculeDelegate?.addMolecules(molecules, sender: self, animation: index < previousTabIndex ? .left : .right) } } diff --git a/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/HeadlineBodyLinkToggle.swift b/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/HeadlineBodyLinkToggle.swift index 7359ed3c..07639dbe 100644 --- a/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/HeadlineBodyLinkToggle.swift +++ b/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/HeadlineBodyLinkToggle.swift @@ -27,7 +27,7 @@ import UIKit headlineBodyLink.headlineBody.styleListItem() addSubview(headlineBodyLink) addSubview(toggle) - NSLayoutConstraint.pinSubviewsCenter(leftView: headlineBodyLink, rightView: toggle) + NSLayoutConstraint.pinViews(leftView: headlineBodyLink, rightView: toggle, alignTop: false) } // MARK: - MVMCoreUIMoleculeViewProtoco diff --git a/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/HeadlineBodyToggle.swift b/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/HeadlineBodyToggle.swift index 324d63da..8df94fa8 100644 --- a/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/HeadlineBodyToggle.swift +++ b/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/HeadlineBodyToggle.swift @@ -31,7 +31,7 @@ import UIKit view.addSubview(headlineBody) view.addSubview(toggle) - NSLayoutConstraint.pinSubviewsCenter(leftView: headlineBody, rightView: toggle) + NSLayoutConstraint.pinViews(leftView: headlineBody, rightView: toggle, alignTop: false) } // MARK:- ModelMoleculeViewProtocol diff --git a/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/LabelToggle.swift b/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/LabelToggle.swift index 3d00b820..f2925cc9 100644 --- a/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/LabelToggle.swift +++ b/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/LabelToggle.swift @@ -28,7 +28,7 @@ import UIKit addSubview(label) addSubview(toggle) label.setContentHuggingPriority(UILayoutPriority.required, for: NSLayoutConstraint.Axis.vertical) - NSLayoutConstraint.pinSubviewsCenter(leftView: label, rightView: toggle) + NSLayoutConstraint.pinViews(leftView: label, rightView: toggle, alignTop: false) } // MARK:- ModelMoleculeViewProtocol diff --git a/MVMCoreUI/OtherHandlers/ModelMoleculeDelegateProtocol.swift b/MVMCoreUI/OtherHandlers/ModelMoleculeDelegateProtocol.swift index 8fe1caa5..d3a2fe80 100644 --- a/MVMCoreUI/OtherHandlers/ModelMoleculeDelegateProtocol.swift +++ b/MVMCoreUI/OtherHandlers/ModelMoleculeDelegateProtocol.swift @@ -23,8 +23,8 @@ public protocol MoleculeDelegateProtocol { func removeMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) //optional - func addMolecules(_ molecules: [ListItemModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) - func removeMolecules(_ molecules: [ListItemModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) + func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) + func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) } extension MoleculeDelegateProtocol { @@ -40,11 +40,11 @@ extension MoleculeDelegateProtocol { // Do nothing } - public func addMolecules(_ molecules: [ListItemModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) { + public func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) { // Do nothing } - public func removeMolecules(_ molecules: [ListItemModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) { + public func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) { // Do nothing } } diff --git a/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift b/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift index 3dfc935a..a04f964a 100644 --- a/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift +++ b/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift @@ -74,7 +74,7 @@ import Foundation MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListLeftVariableIconWithRightCaret.self, viewModelClass: ListLeftVariableIconWithRightCaretModel.self) // List items - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: MoleculeTableViewCell.self, viewModelClass: ListItemModel.self) + MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: MoleculeTableViewCell.self, viewModelClass: MoleculeListItemModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: DropDownFilterTableViewCell.self, viewModelClass: DropDownListItemModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: AccordionMoleculeTableViewCell.self, viewModelClass: AccordionListItemModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: TabsTableViewCell.self, viewModelClass: TabsListItemModel.self) diff --git a/MVMCoreUI/Templates/ListPageTemplateModel.swift b/MVMCoreUI/Templates/ListPageTemplateModel.swift index ff899319..4ce4c6f5 100644 --- a/MVMCoreUI/Templates/ListPageTemplateModel.swift +++ b/MVMCoreUI/Templates/ListPageTemplateModel.swift @@ -20,7 +20,7 @@ import Foundation public var isAtomicTabs: Bool? public var header: MoleculeModelProtocol? - public var molecules: [ListItemModelProtocol]? + public var molecules: [ListItemModelProtocol & MoleculeModelProtocol]? public var footer: MoleculeModelProtocol? public var line: LineModel? @@ -28,7 +28,7 @@ import Foundation // MARK: - Initializer //-------------------------------------------------- - public init(pageType: String, screenHeading: String?, molecules: [ListItemModelProtocol]) { + public init(pageType: String, screenHeading: String?, molecules: [ListItemModelProtocol & MoleculeModelProtocol]) { self.pageType = pageType self.screenHeading = screenHeading self.molecules = molecules @@ -57,7 +57,7 @@ import Foundation let typeContainer = try decoder.container(keyedBy: CodingKeys.self) pageType = try typeContainer.decode(String.self, forKey: .pageType) screenHeading = try typeContainer.decodeIfPresent(String.self, forKey: .screenHeading) - molecules = try typeContainer.decodeMoleculesIfPresent(codingKey: .molecules) as? [ListItemModelProtocol] + molecules = try typeContainer.decodeMoleculesIfPresent(codingKey: .molecules) as? [ListItemModelProtocol & MoleculeModelProtocol] isAtomicTabs = try typeContainer.decodeIfPresent(Bool.self, forKey: .isAtomicTabs) header = try typeContainer.decodeMoleculeIfPresent(codingKey: .header) footer = try typeContainer.decodeMoleculeIfPresent(codingKey: .footer) diff --git a/MVMCoreUI/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Templates/MoleculeListTemplate.swift index a088d34a..01d0a5e6 100644 --- a/MVMCoreUI/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeListTemplate.swift @@ -13,7 +13,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol // MARK: - Stored Properties //-------------------------------------------------- - public var moleculesInfo: [(identifier: String, class: AnyClass, molecule: ListItemModelProtocol)]? + public var moleculesInfo: [(identifier: String, class: AnyClass, molecule: (ListItemModelProtocol & MoleculeModelProtocol))]? var observer: NSKeyValueObservation? @@ -176,10 +176,10 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol public override func addMolecules(_ molecules: [[AnyHashable: Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { - var tmpMolecules = [ListItemModelProtocol]() + var tmpMolecules = [ListItemModelProtocol & MoleculeModelProtocol]() molecules.forEach { molecule in - if let data = try? JSONSerialization.data(withJSONObject: molecule), let listItemModel = try? JSONDecoder().decode(ListItemModel.self, from: data) { + if let data = try? JSONSerialization.data(withJSONObject: molecule), let listItemModel = try? JSONDecoder().decode(MoleculeListItemModel.self, from: data) { tmpMolecules.append(listItemModel) } } @@ -205,10 +205,11 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol public override func removeMolecules(_ molecules: [[AnyHashable: Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { - var tmpMolecules = [ListItemModelProtocol]() + var tmpMolecules = [ListItemModelProtocol & MoleculeModelProtocol]() molecules.forEach { molecule in - if let data = try? JSONSerialization.data(withJSONObject: molecule), let listItemModel = try? JSONDecoder().decode(ListItemModel.self, from: data) { + if let data = try? JSONSerialization.data(withJSONObject: molecule), + let listItemModel = try? JSONDecoder().decode(MoleculeListItemModel.self, from: data) { tmpMolecules.append(listItemModel) } } @@ -230,7 +231,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol view.layoutIfNeeded() } - public func addMolecules(_ molecules: [ListItemModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) { + public func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) { // This dispatch is needed to fix a race condition that can occur if this function is called during the table setup. DispatchQueue.main.async { @@ -252,7 +253,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol } } - public func removeMolecules(_ molecules: [ListItemModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) { + public func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) { var indexPaths: [IndexPath] = [] //TODO: cehck for molecule protocola eqality @@ -274,7 +275,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol //-------------------------------------------------- /// Returns the (identifier, class) of the molecule for the given map. - func getMoleculeInfo(with listItem: ListItemModelProtocol?) -> (identifier: String, class: AnyClass, molecule: ListItemModelProtocol)? { + func getMoleculeInfo(with listItem: (ListItemModelProtocol & MoleculeModelProtocol)?) -> (identifier: String, class: AnyClass, molecule: ListItemModelProtocol & MoleculeModelProtocol)? { guard let listItem = listItem, let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(listItem), @@ -285,9 +286,9 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol } /// Sets up the molecule list and ensures no errors loading all content. - func getMoleculeInfoList() -> [(identifier: String, class: AnyClass, molecule: ListItemModelProtocol)]? { + func getMoleculeInfoList() -> [(identifier: String, class: AnyClass, molecule: (ListItemModelProtocol & MoleculeModelProtocol))]? { - var moleculeList: [(identifier: String, class: AnyClass, molecule: ListItemModelProtocol)] = [] + var moleculeList: [(identifier: String, class: AnyClass, molecule: ListItemModelProtocol & MoleculeModelProtocol)] = [] if let molecules = templateModel?.molecules { for molecule in molecules { diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.h b/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.h index d1b2d470..4503872c 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.h +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.h @@ -30,16 +30,16 @@ - (nullable instancetype)initWithTopAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject animationDelegate:(nullable id )animationDelegate viewToLayout:(nonnull UIView *)viewTolayout; // Used primarily for when button presses will expand or collapse. (Short view button will need to be set manually) -- (nullable instancetype)initWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message buttonTitle:(nullable NSString *)buttonTitle animationDelegate:(nullable id )animationDelegate viewToLayout:(nonnull UIView *)viewTolayout; -- (nullable instancetype)initWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage buttonTitle:(nullable NSString *)buttonTitle animationDelegate:(nullable id )animationDelegate viewToLayout:(nonnull UIView *)viewTolayout; +- (nullable instancetype)initWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message contentColor:(nonnull UIColor *)contentColor buttonTitle:(nullable NSString *)buttonTitle animationDelegate:(nullable id )animationDelegate viewToLayout:(nonnull UIView *)viewTolayout; +- (nullable instancetype)initWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage contentColor:(nonnull UIColor *)contentColor buttonTitle:(nullable NSString *)buttonTitle animationDelegate:(nullable id )animationDelegate viewToLayout:(nonnull UIView *)viewTolayout; // Used when button uses standard action map. -- (nullable instancetype)initWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData animationDelegate:(nullable id )animationDelegate viewToLayout:(nonnull UIView *)viewTolayout; +- (nullable instancetype)initWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage contentColor:(nonnull UIColor *)contentColor actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData animationDelegate:(nullable id )animationDelegate viewToLayout:(nonnull UIView *)viewTolayout; // Convenience change functions - (void)setTopMessage:(nullable NSString *)topMessage; -- (void)setTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData; -- (void)setTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage buttonTitle:(nullable NSString *)buttonTitle userActionHandler:(nullable void (^)(id _Nonnull sender))userActionHandler; +- (void)setTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage contentColor:(nonnull UIColor *)contentColor actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData; +- (void)setTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage contentColor:(nonnull UIColor *)contentColor buttonTitle:(nullable NSString *)buttonTitle userActionHandler:(nullable void (^)(id _Nonnull sender))userActionHandler; // Setters for making buttons expand and collapse the cell. - (void)setButtonPressToExpand; diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m b/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m index 55bb6bfd..f215fa0b 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m @@ -41,10 +41,10 @@ - (void)setupTopAlertWithButton:(MVMCoreUITopAlertMainView *)topAlertWithButton; // Sets up the whole view without setting button action. -- (void)setupViewWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage buttonTitle:(nullable NSString *)buttonTitle; +- (void)setupViewWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage contentColor:(nonnull UIColor *)contentColor buttonTitle:(nullable NSString *)buttonTitle; // Sets up the whole view while setting button action. -- (void)setupViewWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData; +- (void)setupViewWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage contentColor:(nonnull UIColor *)contentColor actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData; @end @@ -97,14 +97,8 @@ [self setupTopAlertWithButton:topAlertWithButton]; // Sets the color - if (topAlertObject.backgroundColor) { - self.backgroundColor = topAlertObject.backgroundColor; - } else { - self.backgroundColor = [[MVMCoreUITopAlertView sharedGlobal] getBackgroundColorForType:topAlertObject.type]; - } - if (topAlertObject.textColor) { - self.shortView.label.textColor = topAlertObject.textColor; - } + self.shortView.label.textColor = topAlertObject.textColor ?: [[MVMCoreUITopAlertView sharedGlobal] getContentColorForType:topAlertObject.type]; + self.backgroundColor = topAlertObject.backgroundColor ?: [[MVMCoreUITopAlertView sharedGlobal] getBackgroundColorForType:topAlertObject.type]; if (topAlertWithButton.label.text.length > 0) { [self expand:NO]; @@ -112,8 +106,10 @@ } else { // Old style, has no top alert and main view is limited. - self.backgroundColor = [[MVMCoreUITopAlertView sharedGlobal] getBackgroundColorForType:topAlertObject.type]; [self setupTopMessage:nil]; - MVMCoreUITopAlertMainView *topAlertWithButton = [[MVMCoreUITopAlertMainView alloc] initWithColor:self.backgroundColor message:topAlertObject.message subMessage:nil closeButton:YES animationDelegate:animationDelegate]; + self.backgroundColor = [[MVMCoreUITopAlertView sharedGlobal] getBackgroundColorForType:topAlertObject.type]; + UIColor *contentColor = [[MVMCoreUITopAlertView sharedGlobal] getContentColorForType:topAlertObject.type]; + [self setupTopMessage:nil]; + MVMCoreUITopAlertMainView *topAlertWithButton = [[MVMCoreUITopAlertMainView alloc] initWithColor:self.backgroundColor contentColor:contentColor message:topAlertObject.message subMessage:nil closeButton:YES animationDelegate:animationDelegate]; [self setupTopAlertWithButton:topAlertWithButton]; [self expand:NO]; } @@ -121,29 +117,29 @@ return self; } -- (nullable instancetype)initWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message buttonTitle:(nullable NSString *)buttonTitle animationDelegate:(nullable id )animationDelegate viewToLayout:(nonnull UIView *)viewTolayout { +- (nullable instancetype)initWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message contentColor:(nonnull UIColor *)contentColor buttonTitle:(nullable NSString *)buttonTitle animationDelegate:(nullable id )animationDelegate viewToLayout:(nonnull UIView *)viewTolayout { if ([self init]) { self.animationDelegate = animationDelegate; self.viewToLayout = viewTolayout; - [self setupViewWithTopMessage:topMessage message:message subMessage:nil buttonTitle:buttonTitle]; + [self setupViewWithTopMessage:topMessage message:message subMessage:nil contentColor:contentColor buttonTitle:buttonTitle]; } return self; } -- (nullable instancetype)initWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage buttonTitle:(nullable NSString *)buttonTitle animationDelegate:(nullable id )animationDelegate viewToLayout:(nonnull UIView *)viewTolayout { +- (nullable instancetype)initWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage contentColor:(nonnull UIColor *)contentColor buttonTitle:(nullable NSString *)buttonTitle animationDelegate:(nullable id )animationDelegate viewToLayout:(nonnull UIView *)viewTolayout { if ([self init]) { self.animationDelegate = animationDelegate; self.viewToLayout = viewTolayout; - [self setupViewWithTopMessage:topMessage message:message subMessage:subMessage buttonTitle:buttonTitle]; + [self setupViewWithTopMessage:topMessage message:message subMessage:subMessage contentColor:contentColor buttonTitle:buttonTitle]; } return self; } -- (nullable instancetype)initWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData animationDelegate:(nullable id )animationDelegate viewToLayout:(nonnull UIView *)viewTolayout { +- (nullable instancetype)initWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage contentColor:(nonnull UIColor *)contentColor actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData animationDelegate:(nullable id )animationDelegate viewToLayout:(nonnull UIView *)viewTolayout { if ([self init]) { self.animationDelegate = animationDelegate; self.viewToLayout = viewTolayout; - [self setupViewWithTopMessage:topMessage message:message subMessage:subMessage actionMap:actionMap additionalData:additionalData]; + [self setupViewWithTopMessage:topMessage message:message subMessage:subMessage contentColor:contentColor actionMap:actionMap additionalData:additionalData]; } return self; } @@ -174,19 +170,19 @@ [NSLayoutConstraint constraintPinSubview:topAlertWithButton pinTop:NO topConstant:0 pinBottom:YES bottomConstant:0 pinLeft:YES leftConstant:0 pinRight:YES rightConstant:0]; } -- (void)setupViewWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage buttonTitle:(nullable NSString *)buttonTitle { +- (void)setupViewWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage contentColor:(nonnull UIColor *)contentColor buttonTitle:(nullable NSString *)buttonTitle { [self setupTopMessage:topMessage]; - MVMCoreUITopAlertMainView *topAlertWithButton = [[MVMCoreUITopAlertMainView alloc] initWithColor:[UIColor clearColor] message:message subMessage:subMessage buttonTitle:buttonTitle userActionHandler:nil]; + MVMCoreUITopAlertMainView *topAlertWithButton = [[MVMCoreUITopAlertMainView alloc] initWithColor:[UIColor clearColor] contentColor:contentColor message:message subMessage:subMessage buttonTitle:buttonTitle userActionHandler:nil]; [self setupTopAlertWithButton:topAlertWithButton]; } -- (void)setupViewWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData { +- (void)setupViewWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage contentColor:(nonnull UIColor *)contentColor actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData { [self setupTopMessage:topMessage]; - MVMCoreUITopAlertMainView *topAlertWithButton = [[MVMCoreUITopAlertMainView alloc] initWithColor:[UIColor clearColor] message:message subMessage:subMessage actionMap:actionMap additionalData:additionalData]; + MVMCoreUITopAlertMainView *topAlertWithButton = [[MVMCoreUITopAlertMainView alloc] initWithColor:[UIColor clearColor] contentColor:contentColor message:message subMessage:subMessage actionMap:actionMap additionalData:additionalData]; [self setupTopAlertWithButton:topAlertWithButton]; } @@ -204,17 +200,17 @@ }]; } -- (void)setTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData { +- (void)setTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage contentColor:(nonnull UIColor *)contentColor actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData { [MVMCoreDispatchUtility performBlockOnMainThread:^{ [self setTopMessage:topMessage]; - [self.buttonView setupWithMessage:message subMessage:subMessage actionMap:actionMap additionalData:additionalData]; + [self.buttonView setupWithMessage:message subMessage:subMessage color:contentColor actionMap:actionMap additionalData:additionalData]; }]; } -- (void)setTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage buttonTitle:(nullable NSString *)buttonTitle userActionHandler:(nullable void (^)(id _Nonnull sender))userActionHandler { +- (void)setTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage contentColor:(nonnull UIColor *)contentColor buttonTitle:(nullable NSString *)buttonTitle userActionHandler:(nullable void (^)(id _Nonnull sender))userActionHandler { [MVMCoreDispatchUtility performBlockOnMainThread:^{ [self setTopMessage:topMessage]; - [self.buttonView setupWithMessage:message subMessage:subMessage buttonTitle:buttonTitle userActionHandler:userActionHandler]; + [self.buttonView setupWithMessage:message subMessage:subMessage color:contentColor buttonTitle:buttonTitle userActionHandler:userActionHandler]; }]; } diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.h b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.h index 50dd9b26..4842fc32 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.h +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.h @@ -22,16 +22,16 @@ // Standard - (nullable instancetype)initWithTopAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject animationDelegate:(nullable id )animationDelegate; -- (nullable instancetype)initWithColor:(nonnull UIColor *)color message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData closeButton:(BOOL)closeButton animationDelegate:(nullable id )animationDelegate; +- (nullable instancetype)initWithColor:(nonnull UIColor *)color contentColor:(nullable UIColor *)contentColor message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData closeButton:(BOOL)closeButton animationDelegate:(nullable id )animationDelegate; // inits with images -- (nullable instancetype)initWithColor:(nonnull UIColor *)color imageURL:(nullable NSString *)imageURL message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData closeButton:(BOOL)closeButton animationDelegate:(nullable id )animationDelegate; -- (nullable instancetype)initWithColor:(nonnull UIColor *)color imageURL:(nullable NSString *)imageURL message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage closeButton:(BOOL)closeButton animationDelegate:(nullable id )animationDelegate; +- (nullable instancetype)initWithColor:(nonnull UIColor *)color contentColor:(nullable UIColor *)contentColor imageURL:(nullable NSString *)imageURL message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData closeButton:(BOOL)closeButton animationDelegate:(nullable id )animationDelegate; +- (nullable instancetype)initWithColor:(nonnull UIColor *)color contentColor:(nullable UIColor *)contentColor imageURL:(nullable NSString *)imageURL message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage closeButton:(BOOL)closeButton animationDelegate:(nullable id )animationDelegate; // Setters for label and button. -- (void)setupWithMessage:(nullable NSString *)message subMessage:(nullable NSString *)subMessage actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData; -- (void)setupWithMessage:(nullable NSString *)message subMessage:(nullable NSString *)subMessage buttonTitle:(nullable NSString *)buttonTitle userActionHandler:(nullable void (^)(id _Nonnull sender))userActionHandler; +- (void)setupWithMessage:(nullable NSString *)message subMessage:(nullable NSString *)subMessage color:(nullable UIColor *)color actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData; +- (void)setupWithMessage:(nullable NSString *)message subMessage:(nullable NSString *)subMessage color:(nullable UIColor *)color buttonTitle:(nullable NSString *)buttonTitle userActionHandler:(nullable void (^)(id _Nonnull sender))userActionHandler; // Setters for button. - (void)setupButtonWithActionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData; @@ -40,13 +40,13 @@ #pragma mark - legacy inits // Legacy init: inits with a label and button, no close button or icon. -- (nullable instancetype)initWithColor:(nonnull UIColor *)color message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData; +- (nullable instancetype)initWithColor:(nonnull UIColor *)color contentColor:(nonnull UIColor *)contentColor message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData; // Legacy init: inits with a label and possible icon and close button. No main button. -- (nullable instancetype)initWithColor:(nonnull UIColor *)color message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage closeButton:(BOOL)closeButton animationDelegate:(nullable id )animationDelegate; +- (nullable instancetype)initWithColor:(nonnull UIColor *)color contentColor:(nonnull UIColor *)contentColor message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage closeButton:(BOOL)closeButton animationDelegate:(nullable id )animationDelegate; // Legacy init: inits with a label and button, no close button or icon. If passing in a block to use for the button, the top alert delegate button functions will not be called. -- (nullable instancetype)initWithColor:(nonnull UIColor *)color message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage buttonTitle:(nullable NSString *)buttonTitle userActionHandler:(nullable void (^)(id _Nonnull sender))userActionHandler; +- (nullable instancetype)initWithColor:(nonnull UIColor *)color contentColor:(nonnull UIColor *)contentColor message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage buttonTitle:(nullable NSString *)buttonTitle userActionHandler:(nullable void (^)(id _Nonnull sender))userActionHandler; @end diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m index e51ffc83..5b87d163 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m @@ -60,52 +60,49 @@ - (nullable instancetype)initWithTopAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject animationDelegate:(nullable id )animationDelegate { if ([self init]) { - if (topAlertObject.backgroundColor) { - self.backgroundColor = topAlertObject.backgroundColor; - } else { - self.backgroundColor = [[MVMCoreUITopAlertView sharedGlobal] getBackgroundColorForType:topAlertObject.type]; - } + UIColor *contentColor = topAlertObject.textColor ?: [[MVMCoreUITopAlertView sharedGlobal] getContentColorForType:topAlertObject.type]; + self.backgroundColor = topAlertObject.backgroundColor ?: [[MVMCoreUITopAlertView sharedGlobal] getBackgroundColorForType:topAlertObject.type]; [self setupViewWithLabelAndImage:topAlertObject.imageNameOrURL topImage:topAlertObject.aboveTextImageString]; [self setupCloseButton:topAlertObject.useCloseButton animationDelegate:animationDelegate]; - [self setupWithMessage:topAlertObject.title subMessage:topAlertObject.message color:topAlertObject.textColor actionMap:topAlertObject.buttonMap additionalData:topAlertObject.additionalData]; + [self setupWithMessage:topAlertObject.title subMessage:topAlertObject.message color:contentColor actionMap:topAlertObject.buttonMap additionalData:topAlertObject.additionalData]; } return self; } -- (nullable instancetype)initWithColor:(nonnull UIColor *)color message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData closeButton:(BOOL)closeButton animationDelegate:(nullable id )animationDelegate { +- (nullable instancetype)initWithColor:(nonnull UIColor *)color contentColor:(nullable UIColor *)contentColor message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData closeButton:(BOOL)closeButton animationDelegate:(nullable id )animationDelegate { // Handles all scenarios. if ([self init]) { self.backgroundColor = color; [self setupViewWithLabelAndImage:nil topImage:nil]; [self setupCloseButton:closeButton animationDelegate:animationDelegate]; - [self setupWithMessage:message subMessage:subMessage actionMap:actionMap additionalData:additionalData]; + [self setupWithMessage:message subMessage:subMessage color:contentColor actionMap:actionMap additionalData:additionalData]; } return self; } #pragma mark - inits with images -- (nullable instancetype)initWithColor:(nonnull UIColor *)color imageURL:(nullable NSString *)imageURL message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData closeButton:(BOOL)closeButton animationDelegate:(nullable id )animationDelegate { +- (nullable instancetype)initWithColor:(nonnull UIColor *)color contentColor:(nullable UIColor *)contentColor imageURL:(nullable NSString *)imageURL message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData closeButton:(BOOL)closeButton animationDelegate:(nullable id )animationDelegate { // Handles all scenarios. if ([self init]) { self.backgroundColor = color; [self setupViewWithLabelAndImage:imageURL topImage:nil]; [self setupCloseButton:closeButton animationDelegate:animationDelegate]; - [self setupWithMessage:message subMessage:subMessage actionMap:actionMap additionalData:additionalData]; + [self setupWithMessage:message subMessage:subMessage color:contentColor actionMap:actionMap additionalData:additionalData]; } return self; } -- (nullable instancetype)initWithColor:(nonnull UIColor *)color imageURL:(nullable NSString *)imageURL message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage closeButton:(BOOL)closeButton animationDelegate:(nullable id )animationDelegate { +- (nullable instancetype)initWithColor:(nonnull UIColor *)color contentColor:(nullable UIColor *)contentColor imageURL:(nullable NSString *)imageURL message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage closeButton:(BOOL)closeButton animationDelegate:(nullable id )animationDelegate { // No main button. if ([self init]) { self.backgroundColor = color; [self setupViewWithLabelAndImage:imageURL topImage:nil]; [self setupCloseButton:closeButton animationDelegate:animationDelegate]; - [self setupWithMessage:message subMessage:subMessage buttonTitle:nil userActionHandler:NULL]; + [self setupWithMessage:message subMessage:subMessage color:contentColor buttonTitle:nil userActionHandler:NULL]; } return self; } @@ -173,7 +170,7 @@ if (closeButton && !self.closeButton) { self.closeButton = [self addCloseButtonWithAnimationDelegate:animationDelegate]; - [self.closeButton setTintColor:self.contentColor ?:[UIColor whiteColor]]; + [self.closeButton setTintColor:self.contentColor ?: [UIColor whiteColor]]; } else if (!closeButton && self.closeButton) { [self.closeButton removeFromSuperview]; self.closeButton = nil; @@ -241,17 +238,19 @@ }]; } -- (void)setupWithMessage:(nullable NSString *)message subMessage:(nullable NSString *)subMessage actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData { - [self setupWithMessage:message subMessage:subMessage color:nil actionMap:actionMap additionalData:additionalData]; -} - -- (void)setupWithMessage:(nullable NSString *)message subMessage:(nullable NSString *)subMessage buttonTitle:(nullable NSString *)buttonTitle userActionHandler:(nullable void (^)(id _Nonnull sender))userActionHandler { +- (void)setupWithMessage:(nullable NSString *)message subMessage:(nullable NSString *)subMessage color:(nullable UIColor *)color buttonTitle:(nullable NSString *)buttonTitle userActionHandler:(nullable void (^)(id _Nonnull sender))userActionHandler { self.message = message; self.subMessage = subMessage; + self.contentColor = color; [MVMCoreDispatchUtility performBlockOnMainThread:^{ // Sets the string - self.label.attributedText = [MVMCoreUITopAlertBaseView getStringForMessage:message subMessage:subMessage color:nil]; + self.label.attributedText = [MVMCoreUITopAlertBaseView getStringForMessage:message subMessage:subMessage color:color]; + + // Sets the color + if (color) { + [self.closeButton setTintColor:color]; + } // Sets the button [self setupButtonWithButtonTitle:buttonTitle userActionHandler:userActionHandler]; @@ -284,36 +283,36 @@ #pragma mark - legacy inits -- (nullable instancetype)initWithColor:(nonnull UIColor *)color message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData { +- (nullable instancetype)initWithColor:(nonnull UIColor *)color contentColor:(nonnull UIColor *)contentColor message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData { // No icon or close button. if ([self init]) { self.backgroundColor = color; [self setupViewWithLabelAndImage:nil topImage:nil]; - [self setupWithMessage:message subMessage:subMessage actionMap:actionMap additionalData:additionalData]; + [self setupWithMessage:message subMessage:subMessage color:contentColor actionMap:actionMap additionalData:additionalData]; } return self; } -- (nullable instancetype)initWithColor:(nonnull UIColor *)color message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage closeButton:(BOOL)closeButton animationDelegate:(nullable id )animationDelegate { +- (nullable instancetype)initWithColor:(nonnull UIColor *)color contentColor:(nonnull UIColor *)contentColor message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage closeButton:(BOOL)closeButton animationDelegate:(nullable id )animationDelegate { // No main button. if ([self init]) { self.backgroundColor = color; [self setupViewWithLabelAndImage:nil topImage:nil]; + [self setupWithMessage:message subMessage:subMessage color:contentColor buttonTitle:nil userActionHandler:NULL]; [self setupCloseButton:closeButton animationDelegate:animationDelegate]; - [self setupWithMessage:message subMessage:subMessage buttonTitle:nil userActionHandler:NULL]; } return self; } -- (nullable instancetype)initWithColor:(nonnull UIColor *)color message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage buttonTitle:(nullable NSString *)buttonTitle userActionHandler:(nullable void (^)(id _Nonnull sender))userActionHandler { +- (nullable instancetype)initWithColor:(nonnull UIColor *)color contentColor:(nonnull UIColor *)contentColor message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage buttonTitle:(nullable NSString *)buttonTitle userActionHandler:(nullable void (^)(id _Nonnull sender))userActionHandler { // No icon or close button. Custom button action. if ([self init]) { self.backgroundColor = color; [self setupViewWithLabelAndImage:nil topImage:nil]; - [self setupWithMessage:message subMessage:subMessage buttonTitle:buttonTitle userActionHandler:userActionHandler]; + [self setupWithMessage:message subMessage:subMessage color:contentColor buttonTitle:buttonTitle userActionHandler:userActionHandler]; } return self; } diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.h b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.h index 9850cca3..ca9520f3 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.h +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.h @@ -47,9 +47,12 @@ // Can be subclassed for custom views. - (nonnull MVMCoreUITopAlertBaseView *)topAlertViewForTopAlertObject:(nullable MVMCoreTopAlertObject *)topAlertObject animationDelegate:(nonnull id )animationDelegate statusBarColor:(UIColor *_Nullable *_Nullable)statusBarColor; -// Get the background color based on the type +/// Get the background color based on the type - (nonnull UIColor *)getBackgroundColorForType:(nullable NSString *)type; +/// Get the content color based on the type +- (nonnull UIColor *)getContentColorForType:(nullable NSString *)type; + // Set the status bar color. Used for updating the status bar when the view changes. - (void)setStatusBarColor:(nullable UIColor *)statusBarColor statusBarStyle:(UIStatusBarStyle)style; diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.m b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.m index b65f7423..947e6ffc 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.m +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.m @@ -114,6 +114,14 @@ NSString * const MFAccTopAlertClosed = @"Top alert notification is closed."; } } +- (nonnull UIColor *)getContentColorForType:(nullable NSString *)type { + if ([type isEqualToString:ValueTypeError]) { + return [UIColor blackColor]; + } else { + return [UIColor whiteColor]; + } +} + - (void)showWithTopAlertObject:(nullable MVMCoreTopAlertObject *)topAlertObject animationDelegate:(nonnull id )animationDelegate completionHandler:(void (^ __nullable)(BOOL finished))completionHandler { self.animationDelegate = animationDelegate; @@ -126,7 +134,8 @@ NSString * const MFAccTopAlertClosed = @"Top alert notification is closed."; MVMCoreUITopAlertBaseView *view = [self topAlertViewForTopAlertObject:topAlertObject animationDelegate:animationDelegate statusBarColor:&statusBarColor]; if (!statusBarColor) { statusBarColor = [UIColor whiteColor]; - } + } +#warning This logic is incomplete, it is possible to show the wrong status bar color here if the background is yellow or pumpkin. UIStatusBarStyle statusBarStyle = statusBarColor == [UIColor whiteColor] ? UIStatusBarStyleDefault : UIStatusBarStyleLightContent; [self setStatusBarColor:statusBarColor statusBarStyle:statusBarStyle]; [self showAlertView:view topAlertObject:topAlertObject completionHandler:completionHandler];