From a8e13263e6f224e76301ea565dbc29b6dafb6a7d Mon Sep 17 00:00:00 2001 From: Damodaram Date: Mon, 14 Sep 2020 16:56:38 +0530 Subject: [PATCH 1/8] added action attribute for radiobutton --- MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift | 5 ++++- MVMCoreUI/Atomic/Atoms/Selectors/RadioButtonModel.swift | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift index 371d3f7a..239a368b 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift @@ -9,7 +9,7 @@ import UIKit -@objcMembers open class RadioButton: Control { +@objcMembers open class RadioButton: Control,MFButtonProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -99,6 +99,9 @@ import UIKit } else { isSelected = !isSelected } + if let actionModel = radioModel?.action, isSelected { + Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: nil) + } _ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate) setNeedsDisplay() } diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButtonModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButtonModel.swift index ea1a4627..7d50cf56 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButtonModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButtonModel.swift @@ -26,6 +26,7 @@ open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol { public var baseValue: AnyHashable? public var groupName: String = FormValidator.defaultGroupName public var fieldKey: String? + public var action: ActionModelProtocol? //-------------------------------------------------- // MARK: - Keys @@ -39,6 +40,7 @@ open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol { case fieldValue case fieldKey case groupName + case action } //-------------------------------------------------- @@ -81,6 +83,7 @@ open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol { self.groupName = groupName } fieldValue = try typeContainer.decodeIfPresent(String.self, forKey: .fieldValue) + action = try typeContainer.decodeModelIfPresent(codingKey: .action) } public func encode(to encoder: Encoder) throws { @@ -92,5 +95,6 @@ open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol { try container.encodeIfPresent(fieldKey, forKey: .fieldKey) try container.encodeIfPresent(groupName, forKey: .groupName) try container.encodeIfPresent(fieldValue, forKey: .fieldValue) + try container.encodeModelIfPresent(action, forKey: .action) } } From c76911e76e4a4adb1661beeaf444861edea9b2bb Mon Sep 17 00:00:00 2001 From: Damodaram Date: Mon, 14 Sep 2020 20:07:56 +0530 Subject: [PATCH 2/8] review changes. --- MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift index 239a368b..e1f3ab93 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift @@ -9,7 +9,7 @@ import UIKit -@objcMembers open class RadioButton: Control,MFButtonProtocol { +@objcMembers open class RadioButton: Control, MFButtonProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -100,7 +100,7 @@ import UIKit isSelected = !isSelected } if let actionModel = radioModel?.action, isSelected { - Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: nil) + Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: nil) } _ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate) setNeedsDisplay() From d3a9e64b55704a3fff74d56bc16ca01be46f4f00 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Mon, 14 Sep 2020 21:39:01 -0400 Subject: [PATCH 3/8] molecular top alert quick draft --- MVMCoreUI.xcodeproj/project.pbxproj | 16 ++ MVMCoreUI/Atomic/MoleculeObjectMapping.swift | 4 + .../Atomic/TopNotificationModel.swift | 80 ++++++ .../MVMCoreUITopAlertExpandableView.m | 15 ++ .../TopAlert/MVMCoreUITopAlertMainView.h | 3 + .../TopAlert/MVMCoreUITopAlertMainView.m | 11 + .../MVMCoreUITopAlertView+Extension.swift | 252 ++++++++++++++++++ MVMCoreUI/TopAlert/MVMCoreUITopAlertView.m | 25 +- 8 files changed, 397 insertions(+), 9 deletions(-) create mode 100644 MVMCoreUI/TopAlert/Atomic/TopNotificationModel.swift create mode 100644 MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index b61c3aa1..f9a0cdb3 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -301,6 +301,8 @@ D2092357244FA1EF0044AD09 /* ThreeLayerModelBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2092356244FA1EF0044AD09 /* ThreeLayerModelBase.swift */; }; D20923592450ECE00044AD09 /* TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20923582450ECE00044AD09 /* TableView.swift */; }; D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */; }; + D20C7009250BF99B0095B21C /* TopNotificationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20C7008250BF99B0095B21C /* TopNotificationModel.swift */; }; + D20C700B250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20C700A250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift */; }; D20FB165241A5D75004AFC3A /* NavigationItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20FB164241A5D75004AFC3A /* NavigationItemModel.swift */; }; D213347723843825008E41B3 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = D213347623843825008E41B3 /* Line.swift */; }; D21B7F602437C5BC00051ABF /* MoleculeStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21B7F5E2437C5BC00051ABF /* MoleculeStackView.swift */; }; @@ -782,6 +784,8 @@ D2092356244FA1EF0044AD09 /* ThreeLayerModelBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerModelBase.swift; sourceTree = ""; }; D20923582450ECE00044AD09 /* TableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableView.swift; sourceTree = ""; }; D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = ""; }; + D20C7008250BF99B0095B21C /* TopNotificationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopNotificationModel.swift; sourceTree = ""; }; + D20C700A250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreUITopAlertView+Extension.swift"; sourceTree = ""; }; D20FB164241A5D75004AFC3A /* NavigationItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationItemModel.swift; sourceTree = ""; }; D213347623843825008E41B3 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = ""; }; D21B7F5E2437C5BC00051ABF /* MoleculeStackView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeStackView.swift; sourceTree = ""; }; @@ -1258,6 +1262,14 @@ path = FourColumn; sourceTree = ""; }; + D20C7007250BF9440095B21C /* Atomic */ = { + isa = PBXGroup; + children = ( + D20C7008250BF99B0095B21C /* TopNotificationModel.swift */, + ); + path = Atomic; + sourceTree = ""; + }; D20FFFB42451E32100A31DA2 /* Device */ = { isa = PBXGroup; children = ( @@ -1757,6 +1769,8 @@ D29DF11E21E6851E003B2FB9 /* TopAlert */ = { isa = PBXGroup; children = ( + D20C7007250BF9440095B21C /* Atomic */, + D20C700A250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift */, D29DF12021E6851E003B2FB9 /* MVMCoreUITopAlertView.h */, D29DF12421E6851E003B2FB9 /* MVMCoreUITopAlertView.m */, D29DF12321E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.h */, @@ -2234,6 +2248,7 @@ D253BB8A24574CC5002DE544 /* StackModel.swift in Sources */, 011D95A924057AC7000E3791 /* FormGroupWatcherFieldProtocol.swift in Sources */, BB2BF0EA2452A9BB001D0FC2 /* ListDeviceComplexButtonSmall.swift in Sources */, + D20C700B250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift in Sources */, D236E5B4241FEB1000C38625 /* ListTwoColumnPriceDescription.swift in Sources */, 0AA33B3A2398524F0067DD0F /* Toggle.swift in Sources */, D29DF12F21E6851E003B2FB9 /* MVMCoreUITopAlertMainView.m in Sources */, @@ -2463,6 +2478,7 @@ D253BB9E2458751F002DE544 /* BGImageMoleculeModel.swift in Sources */, AA104AC924472DC7004D2810 /* HeadersH1ButtonModel.swift in Sources */, 0ABD1371237DB0450081388D /* ItemDropdownEntryField.swift in Sources */, + D20C7009250BF99B0095B21C /* TopNotificationModel.swift in Sources */, 8D24041123E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift in Sources */, BB2FB3BD247E7EF200DF73CD /* Tags.swift in Sources */, AA104ADC244734EA004D2810 /* HeadersH1LandingPageHeaderModel.swift in Sources */, diff --git a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift index a08347c7..a598b113 100644 --- a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift +++ b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift @@ -232,6 +232,10 @@ import Foundation MoleculeObjectMapping.shared()?.register(viewClass: LockUpsPlanNames.self, viewModelClass: LockUpsPlanNamesModel.self) MoleculeObjectMapping.shared()?.register(viewClass: LockupsPlanSMLXL.self, viewModelClass: LockupsPlanSMLXLModel.self) + // MARK: - Top Notifications + MoleculeObjectMapping.shared()?.register(viewClass: MVMCoreUITopAlertMainView.self, viewModelClass: NotificationModel.self) + MoleculeObjectMapping.shared()?.register(viewClass: MVMCoreUITopAlertExpandableView.self, viewModelClass: CollapsableNotificationModel.self) + // MARK:- Helper models try? ModelRegistry.register(RuleRequiredModel.self) try? ModelRegistry.register(RuleAnyRequiredModel.self) diff --git a/MVMCoreUI/TopAlert/Atomic/TopNotificationModel.swift b/MVMCoreUI/TopAlert/Atomic/TopNotificationModel.swift new file mode 100644 index 00000000..d6900c85 --- /dev/null +++ b/MVMCoreUI/TopAlert/Atomic/TopNotificationModel.swift @@ -0,0 +1,80 @@ +// +// TopNotification.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 9/11/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +open class TopNotificationModel: Codable { + public var type: String + public var priority = Operation.QueuePriority.normal + public var molecule: MoleculeModelProtocol + public var persistent = false + public var dismissTime = 5 + public var pages: [String]? + public var analyticsData: JSONValueDictionary? + + private enum CodingKeys: String, CodingKey { + case type + case priority + case molecule + case persistent + case dismissTime + case pages + case analyticsData + } + + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + + public init(with type: String, molecule: MoleculeModelProtocol, priority: Operation.QueuePriority = .normal, persistent: Bool = false, dismissTime: Int = 5, pages: [String]? = nil, analyticsData: JSONValueDictionary? = nil) { + self.type = type + self.molecule = molecule + self.priority = priority + self.persistent = persistent + self.dismissTime = dismissTime + self.pages = pages + self.analyticsData = analyticsData + } + + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + type = try typeContainer.decode(String.self, forKey: .type) + molecule = try typeContainer.decodeModel(codingKey: .molecule) + if let priorityPercent = try typeContainer.decodeIfPresent(Float.self, forKey: .priority) { + let scale = Operation.QueuePriority.veryHigh.rawValue - Operation.QueuePriority.veryLow.rawValue + let scaledPercent = (priorityPercent / 100.0) * Float(scale) + self.priority = Operation.QueuePriority(rawValue: Operation.QueuePriority.veryLow.rawValue + Int(scaledPercent)) ?? .normal + } + if let persistent = try typeContainer.decodeIfPresent(Bool.self, forKey: .persistent) { + self.persistent = persistent + } + if let dismissTime = try typeContainer.decodeIfPresent(Int.self, forKey: .dismissTime) { + self.dismissTime = dismissTime + } + pages = try typeContainer.decodeIfPresent([String].self, forKey: .pages) + analyticsData = try typeContainer.decodeIfPresent(JSONValueDictionary.self, forKey: .analyticsData) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(type, forKey: .type) + try container.encodeModel(molecule, forKey: .molecule) + + let scale = Operation.QueuePriority.veryHigh.rawValue - Operation.QueuePriority.veryLow.rawValue + let priorityPercent = Int((Float(priority.rawValue - Operation.QueuePriority.veryLow.rawValue) / Float(scale)) * 100.0) + try container.encode(priorityPercent, forKey: .priority) + try container.encode(persistent, forKey: .persistent) + try container.encode(dismissTime, forKey: .dismissTime) + try container.encodeIfPresent(pages, forKey: .pages) + try container.encodeIfPresent(analyticsData, forKey: .analyticsData) + } +} diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m b/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m index 55841e3f..7f03fe25 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m @@ -76,6 +76,21 @@ return self; } +- (nonnull instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + self.translatesAutoresizingMaskIntoConstraints = NO; + self.clipsToBounds = YES; + _collapseAutomaticallyAfterExpanded = YES; + self.viewToLayout = MVMCoreUITopAlertView.sharedGlobal.superview; + self.expanded = NO; + [self setupTopMessage:nil]; + MVMCoreUITopAlertMainView *topAlertWithButton = [[MVMCoreUITopAlertMainView alloc] initWithFrame:frame]; + [self setupTopAlertWithButton:topAlertWithButton]; + } + return self; +} + + - (nullable instancetype)initWithTopAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject animationDelegate:(nullable id )animationDelegate viewToLayout:(nonnull UIView *)viewTolayout { if (self = [self init]) { self.animationDelegate = animationDelegate; diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.h b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.h index 0f75ad9c..137ac168 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.h +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.h @@ -37,6 +37,9 @@ - (void)setupButtonWithActionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData; - (void)setupButtonWithButtonTitle:(nullable NSString *)buttonTitle userActionHandler:(nullable void (^)(id _Nonnull sender))userActionHandler; +// Setters for close button. +- (void)setupCloseButton:(BOOL)closeButton animationDelegate:(nullable id )animationDelegate; + #pragma mark - legacy inits // Legacy init: inits with a label and button, no close button or icon. diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m index 23beeb64..6c1da1fd 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m @@ -60,6 +60,17 @@ return self; } +- (nonnull instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + self.translatesAutoresizingMaskIntoConstraints = NO; + self.clipsToBounds = YES; + self.height = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:96]; + self.height.active = YES; + [self setupViewWithLabelAndImage:nil topImage:nil]; + } + return self; +} + - (nullable instancetype)initWithTopAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject animationDelegate:(nullable id )animationDelegate { if (self = [self init]) { UIColor *contentColor = topAlertObject.textColor ?: [[MVMCoreUITopAlertView sharedGlobal] getContentColorForType:topAlertObject.type]; diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift new file mode 100644 index 00000000..5b4cd3b7 --- /dev/null +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift @@ -0,0 +1,252 @@ +// +// MVMCoreUITopAlertView+Extension.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 9/11/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public extension MVMCoreTopAlertObject { + static func create(with model: TopNotificationModel) -> Self { + let object = self.init() + object.persistent = model.persistent + object.type = model.type + object.topAlertDismissTime = model.dismissTime + object.queuePriority = model.priority + object.useNewStyle = true + object.json = model.toJSON() + return object + } +} + +public extension MVMCoreAlertHandler { + + /// Decodes the top alert json to a model. + static func decode(json: [AnyHashable: Any], delegateObject: MVMCoreUIDelegateObject?) throws -> TopNotificationModel { + let data = try JSONSerialization.data(withJSONObject: json) + let decoder = JSONDecoder() + if let delegateObject = delegateObject { + try decoder.add(delegateObject: delegateObject) + } + return try decoder.decode(TopNotificationModel.self, from: data) + } + + /// Shows the top alert with the json payload. + func showTopAlert(with json: [AnyHashable: Any], delegateObject: MVMCoreUIDelegateObject?) { + do { + let model = try Self.decode(json: json, delegateObject: delegateObject) + showTopAlert(with: model, delegateObject: delegateObject) + } catch { + if let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: "\(self)") { + MVMCoreUILoggingHandler.shared()?.addError(toLog: errorObject) + } + } + } + + /// Shows the top alert with the model. + func showTopAlert(with model: TopNotificationModel, delegateObject: MVMCoreUIDelegateObject?) { + let object = MVMCoreTopAlertObject.create(with: model) + guard let pages = model.pages else { + showTopAlert(with: object) + return + } + guard let controller = MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() as? MVMCoreViewControllerProtocol, + let pageType = controller.pageType, + pages.contains(pageType) else { + showTopAlert(with: object) + // add + return + } + showTopAlert(with: object) + } +} + +protocol StatusBarUI { + func getStatusBarUI() -> (color: UIColor, style: UIStatusBarStyle) +} + +public extension MVMCoreUITopAlertView { + + /// Registers with the notification center to know when json is updated. + @objc func registerWithNotificationCenter() { + NotificationCenter.default.addObserver(self, selector: #selector(responseJSONUpdated(notification:)), name: NSNotification.Name(rawValue: NotificationResponseLoaded), object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(viewControllerChanged(notification:)), name: NSNotification.Name(rawValue: MVMCoreNotificationViewControllerChanged), object: nil) + } + + /// Checks for new top alert json + @objc func responseJSONUpdated(notification: Notification) { + var jssoonnn = (notification.userInfo?[String(describing: MVMCoreLoadObject.self)] as? MVMCoreLoadObject)?.responseJSON + /*let molecule = CollapsableNotificationModel(with: LabelModel(text: "Top"), headline: LabelModel(text: "Headline")) + //let molecule = NotificationModel(with: LabelModel(text: "Hello")) + molecule.backgroundColor = Color(uiColor: .mvmRed) + molecule.button = ButtonModel(with: "Hi", action: ActionCancelModel()) + molecule.body = LabelModel(text: "Sup") + molecule.closeButton = NotificationXButtonModel() + let model = TopNotificationModel(with: "Testing", molecule: molecule) + model.persistent = false + model.dismissTime = 10 + model.pages = nil//["settingsLanding"] + jssoonnn?.updateValue(model.toJSON()!, forKey: "TopNotification")*/ + guard let json = jssoonnn?.optionalDictionaryForKey("TopNotification") else { return } + // TODO: Top alert view is current delegate. Should move to current view controller eventually? + let delegateObject = MVMCoreUIDelegateObject.create(withDelegateForAll: self) + MVMCoreAlertHandler.shared()?.showTopAlert(with: json, delegateObject: delegateObject) + } + + @objc func viewControllerChanged(notification: Notification) { + guard let controller = MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() as? MVMCoreViewControllerProtocol else { return } + MVMCoreAlertHandler.shared()?.checkPagesDependency(for: controller.pageType) + } + + @objc func molecule(for topAlertObject: MVMCoreTopAlertObject, statusBarColor: AutoreleasingUnsafeMutablePointer?, statusBarStyle: UnsafeMutablePointer?) -> MVMCoreUITopAlertBaseView? { + do { + let delegateObject = MVMCoreUIDelegateObject.create(withDelegateForAll: self) + guard let json = topAlertObject.json else { return nil } + let model = try MVMCoreAlertHandler.decode(json: json, delegateObject: delegateObject) + guard let molecule = MoleculeObjectMapping.shared()?.createMolecule(model.molecule, delegateObject: delegateObject, additionalData: nil), + let view = molecule as? MVMCoreUITopAlertBaseView else { + throw ModelRegistry.Error.decoderOther(message: "Molecule not a top alert") + } + if let casteView = view as? StatusBarUI { + let statusBarUI = casteView.getStatusBarUI() + statusBarColor?.pointee = statusBarUI.color + statusBarStyle?.pointee = statusBarUI.style + } + return view + } catch { + if let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: "\(self)") { + MVMCoreUILoggingHandler.shared()?.addError(toLog: errorObject) + } + return nil + } + } + /* + /// Shows the top alert with the json payload. + func showTopAlert(with json: [AnyHashable: Any], delegateObject: MVMCoreUIDelegateObject?) { + /*do { + let model = try decode(json: json, delegateObject: delegateObject) + showTopAlert(with: model, delegateObject: delegateObject) + } catch { + if let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: "\(self)") { + MVMCoreUILoggingHandler.shared()?.addError(toLog: errorObject) + } + }*/ + } + + /// Shows the top alert with the model. + func showTopAlert(with model: TopNotificationModel, delegateObject: MVMCoreUIDelegateObject?) { + if let molecule = MoleculeObjectMapping.shared()?.createMolecule(model.molecule, delegateObject: delegateObject, additionalData: nil) { + + } + }*/ +} + +public class NotificationXButtonModel: Codable { + public var color: Color? + public var action: ActionModelProtocol? + + private enum CodingKeys: String, CodingKey { + case color + case action + } + + public init() { + } + + public required init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + color = try typeContainer.decodeIfPresent(Color.self, forKey: .color) + action = try typeContainer.decodeModelIfPresent(codingKey: .action) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(color, forKey: .color) + try container.encodeModelIfPresent(action, forKey: .action) + } +} + +public class NotificationModel: MoleculeModelProtocol { + public static var identifier: String = "notification" + public var moleculeName: String = NotificationModel.identifier + public var backgroundColor: Color? + public var headline: LabelModel + public var body: LabelModel? + public var button: ButtonModel? + public var closeButton: NotificationXButtonModel? + + init(with headline: LabelModel) { + self.headline = headline + } +} + +extension MVMCoreUITopAlertMainView: MoleculeViewProtocol { + public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + guard let model = model as? NotificationModel else { return } + backgroundColor = model.backgroundColor?.uiColor ?? .mvmGreen + var actionMap = model.button?.action.toJSON() + if let title = model.button?.title { + actionMap?.updateValue(title, forKey: KeyTitle) + } + setupCloseButton(model.closeButton != nil, animationDelegate: MVMCoreUITopAlertView.sharedGlobal()?.animationDelegate) + setup(withMessage: model.headline.text, subMessage: model.body?.text, color: model.headline.textColor?.uiColor ?? .white, actionMap: actionMap, additionalData: nil) + } +} + +public class CollapsableNotificationModel: MoleculeModelProtocol { + public static var identifier: String = "collapsableNotification" + public var moleculeName: String = CollapsableNotificationModel.identifier + public var backgroundColor: Color? + public var topLabel: LabelModel + //public var topAction: ActionModelProtocol? + public var headline: LabelModel + public var body: LabelModel? + public var button: ButtonModel? + public var closeButton: NotificationXButtonModel? + public var alwaysShowCollapsedLabel = false + public var collapseTime: Int = 5 + public var initiallyCollapsed = false + //public var pages: [NSString]? + + init(with topLabel: LabelModel, headline: LabelModel) { + self.topLabel = topLabel + self.headline = headline + } +} + +extension MVMCoreUITopAlertExpandableView: MoleculeViewProtocol { + public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + guard let model = model as? CollapsableNotificationModel else { return } + backgroundColor = model.backgroundColor?.uiColor ?? .mvmGreen + collapseTime = model.collapseTime + onlyShowTopMessageWhenCollapsed = !model.alwaysShowCollapsedLabel + + var actionMap = model.button?.action.toJSON() + if let title = model.button?.title { + actionMap?.updateValue(title, forKey: KeyTitle) + } + buttonView?.setupCloseButton(model.closeButton != nil, animationDelegate: MVMCoreUITopAlertView.sharedGlobal()?.animationDelegate) + setTopMessage(model.topLabel.text, message: model.headline.text, subMessage: model.body?.text, contentColor: model.headline.textColor?.uiColor ?? .white, actionMap: actionMap, additionalData: nil) + expand(false) + //[MVMCoreUITopAlertBaseView addActionToButton:survivalMode.shortView.button actionMap:topAlertObject.buttonMap additionalData:topAlertObject.additionalData]; + // survivalMode.shortView.label.accessibilityTraits = UIAccessibilityTraitButton; + } +} + +extension MVMCoreUITopAlertExpandableView: StatusBarUI { + func getStatusBarUI() -> (color: UIColor, style: UIStatusBarStyle) { + if shortView?.label?.text?.count ?? 0 > 0 { + let color = backgroundColor ?? UIColor.mvmGreen + var greyScale: CGFloat = 0 + if shortView?.label?.textColor.getWhite(&greyScale, alpha: nil) ?? false { + return (color, greyScale > 0.5 ? .lightContent : .default) + } else { + return (color, .default) + } + } else { + return (.white, .default) + } + } +} diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.m b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.m index 7efa15a3..903a24d3 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.m +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.m @@ -16,6 +16,7 @@ #import "NSLayoutConstraint+MFConvenience.h" #import "MVMCoreUISession.h" #import "MVMCoreUIUtility.h" +#import @import MVMCore.MVMCoreTopAlertObject; @import MVMCore.MVMCoreLoadHandler; @import MVMCore.MVMCoreNavigationHandler; @@ -105,6 +106,8 @@ NSString * const MFAccTopAlertClosed = @"Top alert notification is closed."; self.statusBarView = statusBarView; [self setStatusBarColor:[UIColor whiteColor] statusBarStyle:UIStatusBarStyleDefault]; + + [self registerWithNotificationCenter]; } } @@ -122,18 +125,22 @@ NSString * const MFAccTopAlertClosed = @"Top alert notification is closed."; } - (nonnull MVMCoreUITopAlertBaseView *)topAlertViewForTopAlertObject:(nullable MVMCoreTopAlertObject *)topAlertObject animationDelegate:(nonnull id )animationDelegate statusBarColor:(UIColor *_Nullable *_Nullable)statusBarColor statusBarStyle:(UIStatusBarStyle *_Nullable)statusBarStyle { - MVMCoreUITopAlertExpandableView *view = [[MVMCoreUITopAlertExpandableView alloc] initWithTopAlertObject:topAlertObject animationDelegate:animationDelegate viewToLayout:self.superview]; - if (statusBarColor && view.shortView.label.text) { - *statusBarColor = view.backgroundColor; - - if (statusBarStyle) { - CGFloat greyScale = 0; - if ([view.shortView.label.textColor getWhite:&greyScale alpha:nil]) { - *statusBarStyle = greyScale > 0.5 ? UIStatusBarStyleLightContent : UIStatusBarStyleDefault; + if (topAlertObject.json) { + return [self moleculeFor:topAlertObject statusBarColor:statusBarColor statusBarStyle:statusBarStyle]; + } else { + MVMCoreUITopAlertExpandableView *view = [[MVMCoreUITopAlertExpandableView alloc] initWithTopAlertObject:topAlertObject animationDelegate:animationDelegate viewToLayout:self.superview]; + if (statusBarColor && view.shortView.label.text) { + *statusBarColor = view.backgroundColor; + + if (statusBarStyle) { + CGFloat greyScale = 0; + if ([view.shortView.label.textColor getWhite:&greyScale alpha:nil]) { + *statusBarStyle = greyScale > 0.5 ? UIStatusBarStyleLightContent : UIStatusBarStyleDefault; + } } } + return view; } - return view; } - (nonnull UIColor *)getBackgroundColorForType:(nullable NSString *)type { From 450b4e3e3dfd77d5d50f7c922f976e2c14539de8 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 15 Sep 2020 11:31:10 -0400 Subject: [PATCH 4/8] Comments, organizing, init fix --- MVMCoreUI.xcodeproj/project.pbxproj | 38 +++- .../CollapsableNotificationModel.swift | 82 +++++++ ...reUITopAlertExpandableView+Extension.swift | 50 +++++ .../MVMCoreUITopAlertMainView+Extension.swift | 23 ++ .../NotificationXButtonModel.swift | 34 +++ .../MVMCoreUITopAlertExpandableView.h | 1 + .../MVMCoreUITopAlertExpandableView.m | 29 ++- .../TopAlert/MVMCoreUITopAlertMainView.h | 2 + .../TopAlert/MVMCoreUITopAlertMainView.m | 22 +- .../MVMCoreUITopAlertView+Extension.swift | 208 ++---------------- .../{Atomic => }/TopNotificationModel.swift | 58 ++++- 11 files changed, 321 insertions(+), 226 deletions(-) create mode 100644 MVMCoreUI/Atomic/Molecules/TopNotification/CollapsableNotificationModel.swift create mode 100644 MVMCoreUI/Atomic/Molecules/TopNotification/MVMCoreUITopAlertExpandableView+Extension.swift create mode 100644 MVMCoreUI/Atomic/Molecules/TopNotification/MVMCoreUITopAlertMainView+Extension.swift create mode 100644 MVMCoreUI/Atomic/Molecules/TopNotification/NotificationXButtonModel.swift rename MVMCoreUI/TopAlert/{Atomic => }/TopNotificationModel.swift (60%) diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index f9a0cdb3..b67f6235 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -459,6 +459,11 @@ D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */; }; D2C521A923EDE79E00CA2634 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2C521A823EDE79E00CA2634 /* ViewController.swift */; }; D2C78CD224228BBD00B69FDE /* ActionOpenPanelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2C78CD124228BBD00B69FDE /* ActionOpenPanelModel.swift */; }; + D2CAC7CB251104E100C75681 /* NotificationXButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CAC7CA251104E100C75681 /* NotificationXButtonModel.swift */; }; + D2CAC7CD251104FE00C75681 /* NotificationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CAC7CC251104FE00C75681 /* NotificationModel.swift */; }; + D2CAC7CF2511052300C75681 /* CollapsableNotificationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CAC7CE2511052300C75681 /* CollapsableNotificationModel.swift */; }; + D2CAC7D12511058C00C75681 /* MVMCoreUITopAlertMainView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CAC7D02511058C00C75681 /* MVMCoreUITopAlertMainView+Extension.swift */; }; + D2CAC7D3251105A700C75681 /* MVMCoreUITopAlertExpandableView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CAC7D2251105A700C75681 /* MVMCoreUITopAlertExpandableView+Extension.swift */; }; D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */; }; D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */; }; D2D90B42240463E100DD6EC9 /* MoleculeHeaderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D90B41240463E100DD6EC9 /* MoleculeHeaderModel.swift */; }; @@ -944,6 +949,11 @@ 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 = ""; }; D2C78CD124228BBD00B69FDE /* ActionOpenPanelModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionOpenPanelModel.swift; sourceTree = ""; }; + D2CAC7CA251104E100C75681 /* NotificationXButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationXButtonModel.swift; sourceTree = ""; }; + D2CAC7CC251104FE00C75681 /* NotificationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationModel.swift; sourceTree = ""; }; + D2CAC7CE2511052300C75681 /* CollapsableNotificationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotificationModel.swift; sourceTree = ""; }; + D2CAC7D02511058C00C75681 /* MVMCoreUITopAlertMainView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreUITopAlertMainView+Extension.swift"; sourceTree = ""; }; + D2CAC7D2251105A700C75681 /* MVMCoreUITopAlertExpandableView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreUITopAlertExpandableView+Extension.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 = ""; }; D2D90B41240463E100DD6EC9 /* MoleculeHeaderModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeHeaderModel.swift; sourceTree = ""; }; @@ -1262,14 +1272,6 @@ path = FourColumn; sourceTree = ""; }; - D20C7007250BF9440095B21C /* Atomic */ = { - isa = PBXGroup; - children = ( - D20C7008250BF99B0095B21C /* TopNotificationModel.swift */, - ); - path = Atomic; - sourceTree = ""; - }; D20FFFB42451E32100A31DA2 /* Device */ = { isa = PBXGroup; children = ( @@ -1705,6 +1707,7 @@ D29DF10E21E67A77003B2FB9 /* Molecules */ = { isa = PBXGroup; children = ( + D2CAC7C9251104CB00C75681 /* TopNotification */, D2509ED42472EE0B001BFB9D /* NavigationBar */, D253BB9A24587023002DE544 /* OtherContainers */, D22B38E923F4E07800490EF6 /* DesignedComponents */, @@ -1769,7 +1772,7 @@ D29DF11E21E6851E003B2FB9 /* TopAlert */ = { isa = PBXGroup; children = ( - D20C7007250BF9440095B21C /* Atomic */, + D20C7008250BF99B0095B21C /* TopNotificationModel.swift */, D20C700A250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift */, D29DF12021E6851E003B2FB9 /* MVMCoreUITopAlertView.h */, D29DF12421E6851E003B2FB9 /* MVMCoreUITopAlertView.m */, @@ -2070,6 +2073,18 @@ path = Protocols; sourceTree = ""; }; + D2CAC7C9251104CB00C75681 /* TopNotification */ = { + isa = PBXGroup; + children = ( + D2CAC7CA251104E100C75681 /* NotificationXButtonModel.swift */, + D2CAC7CC251104FE00C75681 /* NotificationModel.swift */, + D2CAC7D02511058C00C75681 /* MVMCoreUITopAlertMainView+Extension.swift */, + D2CAC7CE2511052300C75681 /* CollapsableNotificationModel.swift */, + D2CAC7D2251105A700C75681 /* MVMCoreUITopAlertExpandableView+Extension.swift */, + ); + path = TopNotification; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -2205,6 +2220,7 @@ D28A838123CCB0D800DFE4FC /* AccordionListItemModel.swift in Sources */, D2509ED62472EE2F001BFB9D /* NavigationImageButtonModel.swift in Sources */, 32F8804824765C8400C2ACB3 /* ListLeftVariableNumberedListAllTextAndLinks.swift in Sources */, + D2CAC7CF2511052300C75681 /* CollapsableNotificationModel.swift in Sources */, DBC4391822442197001AB423 /* CaretView.swift in Sources */, C07065C42395677300FBF997 /* Link.swift in Sources */, 0A69F611241BDEA700F7231B /* RuleAnyRequiredModel.swift in Sources */, @@ -2289,6 +2305,7 @@ D29DF12E21E6851E003B2FB9 /* MVMCoreUITopAlertView.m in Sources */, AA1EC59724373985003D6F50 /* ListThreeColumnSpeedTestDividerModel.swift in Sources */, BB1D17E0244EAA30001D2002 /* ListDeviceComplexButtonMediumModel.swift in Sources */, + D2CAC7D3251105A700C75681 /* MVMCoreUITopAlertExpandableView+Extension.swift in Sources */, D29DF2CF21E7C104003B2FB9 /* MFLoadingViewController.m in Sources */, D28A837B23C928DA00DFE4FC /* MoleculeListCellProtocol.swift in Sources */, D28BA74D248589C800B75CB8 /* TabPageModelProtocol.swift in Sources */, @@ -2315,6 +2332,7 @@ D202AFE6242A6A9C00E5BEDF /* UICollectionViewScrollPosition+Extension.swift in Sources */, 8D084AD22410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift in Sources */, 94C0150C2421564A005811A9 /* ActionCollapseNotificationModel.swift in Sources */, + D2CAC7CB251104E100C75681 /* NotificationXButtonModel.swift in Sources */, 014AA73123C5059B006F3E93 /* ListPageTemplateModel.swift in Sources */, AAC23FAF24D92A1E009208DF /* ListThreeColumnSpeedTest.swift in Sources */, D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */, @@ -2370,6 +2388,7 @@ AA633B3124989EC000731E80 /* HeadersH2PricingTwoRowsModel.swift in Sources */, 8DEFA95C243DAC20000D27E5 /* ListThreeColumnDataUsageDividerModel.swift in Sources */, D2092357244FA1EF0044AD09 /* ThreeLayerModelBase.swift in Sources */, + D2CAC7CD251104FE00C75681 /* NotificationModel.swift in Sources */, 0A1B4A96233BB18F005B3FB4 /* CheckboxLabel.swift in Sources */, D20923592450ECE00044AD09 /* TableView.swift in Sources */, BB47A586241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift in Sources */, @@ -2530,6 +2549,7 @@ AA45AA0D24BF0276007A6EA7 /* LockUpsPlanNames.swift in Sources */, 8DE5BECF2456F7B100772E76 /* ListTwoColumnDropdownSelectors.swift in Sources */, D2E1FADF2268B8E700AEFD8C /* ThreeLayerTableViewController.swift in Sources */, + D2CAC7D12511058C00C75681 /* MVMCoreUITopAlertMainView+Extension.swift in Sources */, 0A21DB83235DFBC500C160A2 /* MdnEntryField.swift in Sources */, 0AE98BB723FF18E9004C5109 /* ArrowModel.swift in Sources */, D28A837D23CCA86A00DFE4FC /* TabsListItemModel.swift in Sources */, diff --git a/MVMCoreUI/Atomic/Molecules/TopNotification/CollapsableNotificationModel.swift b/MVMCoreUI/Atomic/Molecules/TopNotification/CollapsableNotificationModel.swift new file mode 100644 index 00000000..09860232 --- /dev/null +++ b/MVMCoreUI/Atomic/Molecules/TopNotification/CollapsableNotificationModel.swift @@ -0,0 +1,82 @@ +// +// CollapsableNotificationModel.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 9/15/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public class CollapsableNotificationModel: MoleculeModelProtocol { + public static var identifier: String = "collapsableNotification" + public var moleculeName: String = CollapsableNotificationModel.identifier + public var backgroundColor: Color? + public var topLabel: LabelModel + public var topAction: ActionModelProtocol? + public var headline: LabelModel + public var body: LabelModel? + public var button: ButtonModel? + public var closeButton: NotificationXButtonModel? + public var alwaysShowCollapsedLabel = false + public var collapseTime: Int = 5 + public var initiallyCollapsed = false + public var pages: [String]? + + init(with topLabel: LabelModel, headline: LabelModel) { + self.topLabel = topLabel + self.headline = headline + } + + private enum CodingKeys: String, CodingKey { + case moleculeName + case backgroundColor + case topLabel + case topAction + case headline + case body + case button + case closeButton + case alwaysShowCollapsedLabel + case collapseTime + case initiallyCollapsed + case pages + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + topLabel = try typeContainer.decode(LabelModel.self, forKey: .topLabel) + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + topAction = try typeContainer.decodeModelIfPresent(codingKey: .topAction) + headline = try typeContainer.decode(LabelModel.self, forKey: .headline) + body = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .body) + button = try typeContainer.decodeIfPresent(ButtonModel.self, forKey: .button) + closeButton = try typeContainer.decodeIfPresent(NotificationXButtonModel.self, forKey: .closeButton) + if let alwaysShowCollapsedLabel = try typeContainer.decodeIfPresent(Bool.self, forKey: .alwaysShowCollapsedLabel) { + self.alwaysShowCollapsedLabel = alwaysShowCollapsedLabel + } + if let collapseTime = try typeContainer.decodeIfPresent(Int.self, forKey: .collapseTime) { + self.collapseTime = collapseTime + } + if let initiallyCollapsed = try typeContainer.decodeIfPresent(Bool.self, forKey: .initiallyCollapsed) { + self.initiallyCollapsed = initiallyCollapsed + } + pages = try typeContainer.decodeIfPresent([String].self, forKey: .pages) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) + try container.encode(topLabel, forKey: .topLabel) + try container.encodeModelIfPresent(topAction, forKey: .topAction) + try container.encode(headline, forKey: .headline) + try container.encodeIfPresent(body, forKey: .body) + try container.encodeIfPresent(button, forKey: .button) + try container.encodeIfPresent(closeButton, forKey: .closeButton) + try container.encode(alwaysShowCollapsedLabel, forKey: .alwaysShowCollapsedLabel) + try container.encode(collapseTime, forKey: .collapseTime) + try container.encode(initiallyCollapsed, forKey: .initiallyCollapsed) + try container.encodeIfPresent(pages, forKey: .pages) + } +} diff --git a/MVMCoreUI/Atomic/Molecules/TopNotification/MVMCoreUITopAlertExpandableView+Extension.swift b/MVMCoreUI/Atomic/Molecules/TopNotification/MVMCoreUITopAlertExpandableView+Extension.swift new file mode 100644 index 00000000..793edf97 --- /dev/null +++ b/MVMCoreUI/Atomic/Molecules/TopNotification/MVMCoreUITopAlertExpandableView+Extension.swift @@ -0,0 +1,50 @@ +// +// MVMCoreUITopAlertExpandableView+Extension.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 9/15/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +extension MVMCoreUITopAlertExpandableView: MoleculeViewProtocol { + + public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + defaultSetup() + guard let model = model as? CollapsableNotificationModel else { return } + backgroundColor = model.backgroundColor?.uiColor ?? .mvmGreen + collapseTime = model.collapseTime + onlyShowTopMessageWhenCollapsed = !model.alwaysShowCollapsedLabel + + var actionMap = model.button?.action.toJSON() + if let title = model.button?.title { + actionMap?.updateValue(title, forKey: KeyTitle) + } + buttonView?.setupCloseButton(model.closeButton != nil, animationDelegate: MVMCoreUITopAlertView.sharedGlobal()?.animationDelegate) + setTopMessage(model.topLabel.text, message: model.headline.text, subMessage: model.body?.text, contentColor: model.headline.textColor?.uiColor ?? .white, actionMap: actionMap, additionalData: nil) + expand(false) + + if let button = shortView?.button, + let topActionMap = model.topAction?.toJSON() { + MVMCoreUITopAlertBaseView.addAction(to: button, actionMap: topActionMap, additionalData: nil) + shortView?.label?.accessibilityTraits = .button + } + } +} + +extension MVMCoreUITopAlertExpandableView: StatusBarUI { + func getStatusBarUI() -> (color: UIColor, style: UIStatusBarStyle) { + if shortView?.label?.text?.count ?? 0 > 0 { + let color = backgroundColor ?? UIColor.mvmGreen + var greyScale: CGFloat = 0 + if shortView?.label?.textColor.getWhite(&greyScale, alpha: nil) ?? false { + return (color, greyScale > 0.5 ? .lightContent : .default) + } else { + return (color, .default) + } + } else { + return (.white, .default) + } + } +} diff --git a/MVMCoreUI/Atomic/Molecules/TopNotification/MVMCoreUITopAlertMainView+Extension.swift b/MVMCoreUI/Atomic/Molecules/TopNotification/MVMCoreUITopAlertMainView+Extension.swift new file mode 100644 index 00000000..157d6522 --- /dev/null +++ b/MVMCoreUI/Atomic/Molecules/TopNotification/MVMCoreUITopAlertMainView+Extension.swift @@ -0,0 +1,23 @@ +// +// MVMCoreUITopAlertMainView+Extension.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 9/15/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +extension MVMCoreUITopAlertMainView: MoleculeViewProtocol { + public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + defaultSetup() + guard let model = model as? NotificationModel else { return } + backgroundColor = model.backgroundColor?.uiColor ?? .mvmGreen + var actionMap = model.button?.action.toJSON() + if let title = model.button?.title { + actionMap?.updateValue(title, forKey: KeyTitle) + } + setupCloseButton(model.closeButton != nil, animationDelegate: MVMCoreUITopAlertView.sharedGlobal()?.animationDelegate) + setup(withMessage: model.headline.text, subMessage: model.body?.text, color: model.headline.textColor?.uiColor ?? .white, actionMap: actionMap, additionalData: nil) + } +} diff --git a/MVMCoreUI/Atomic/Molecules/TopNotification/NotificationXButtonModel.swift b/MVMCoreUI/Atomic/Molecules/TopNotification/NotificationXButtonModel.swift new file mode 100644 index 00000000..368ec1cf --- /dev/null +++ b/MVMCoreUI/Atomic/Molecules/TopNotification/NotificationXButtonModel.swift @@ -0,0 +1,34 @@ +// +// NotificationXButtonModel.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 9/15/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public class NotificationXButtonModel: Codable { + public var color: Color? + public var action: ActionModelProtocol? + + private enum CodingKeys: String, CodingKey { + case color + case action + } + + public init() { + } + + public required init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + color = try typeContainer.decodeIfPresent(Color.self, forKey: .color) + action = try typeContainer.decodeModelIfPresent(codingKey: .action) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(color, forKey: .color) + try container.encodeModelIfPresent(action, forKey: .action) + } +} diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.h b/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.h index 302474cf..04d41363 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.h +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.h @@ -39,6 +39,7 @@ - (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)defaultSetup; - (void)setTopMessage:(nullable NSString *)topMessage; - (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; diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m b/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m index 7f03fe25..e0eef9d6 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m @@ -76,21 +76,6 @@ return self; } -- (nonnull instancetype)initWithFrame:(CGRect)frame { - if (self = [super initWithFrame:frame]) { - self.translatesAutoresizingMaskIntoConstraints = NO; - self.clipsToBounds = YES; - _collapseAutomaticallyAfterExpanded = YES; - self.viewToLayout = MVMCoreUITopAlertView.sharedGlobal.superview; - self.expanded = NO; - [self setupTopMessage:nil]; - MVMCoreUITopAlertMainView *topAlertWithButton = [[MVMCoreUITopAlertMainView alloc] initWithFrame:frame]; - [self setupTopAlertWithButton:topAlertWithButton]; - } - return self; -} - - - (nullable instancetype)initWithTopAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject animationDelegate:(nullable id )animationDelegate viewToLayout:(nonnull UIView *)viewTolayout { if (self = [self init]) { self.animationDelegate = animationDelegate; @@ -158,6 +143,20 @@ return self; } +- (void)defaultSetup { + if (!self.shortView) { + self.translatesAutoresizingMaskIntoConstraints = NO; + self.clipsToBounds = YES; + _collapseAutomaticallyAfterExpanded = YES; + self.viewToLayout = MVMCoreUITopAlertView.sharedGlobal.superview; + self.expanded = NO; + [self setupTopMessage:nil]; + MVMCoreUITopAlertMainView *topAlertWithButton = [[MVMCoreUITopAlertMainView alloc] init]; + [topAlertWithButton defaultSetup]; + [self setupTopAlertWithButton:topAlertWithButton]; + } +} + - (void)setupTopMessage:(nullable NSString *)topMessage { MVMCoreUITopAlertShortView *shortView = [[MVMCoreUITopAlertShortView alloc] initWithColor:[UIColor clearColor] message:nil actionMap:nil additionalData:nil topAlertObject:nil]; diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.h b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.h index 137ac168..b08ca00b 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.h +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.h @@ -28,6 +28,8 @@ - (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; +// Sets up without image +- (void)defaultSetup; // Setters for label and button. - (void)setupWithMessage:(nullable NSString *)message subMessage:(nullable NSString *)subMessage color:(nullable UIColor *)color actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData; diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m index 6c1da1fd..c817059d 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m @@ -60,17 +60,6 @@ return self; } -- (nonnull instancetype)initWithFrame:(CGRect)frame { - if (self = [super initWithFrame:frame]) { - self.translatesAutoresizingMaskIntoConstraints = NO; - self.clipsToBounds = YES; - self.height = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:96]; - self.height.active = YES; - [self setupViewWithLabelAndImage:nil topImage:nil]; - } - return self; -} - - (nullable instancetype)initWithTopAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject animationDelegate:(nullable id )animationDelegate { if (self = [self init]) { UIColor *contentColor = topAlertObject.textColor ?: [[MVMCoreUITopAlertView sharedGlobal] getContentColorForType:topAlertObject.type]; @@ -121,6 +110,17 @@ } #pragma mark - setup + +- (void)defaultSetup { + if (!self.label) { + self.translatesAutoresizingMaskIntoConstraints = NO; + self.clipsToBounds = YES; + self.height = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:96]; + self.height.active = YES; + [self setupViewWithLabelAndImage:nil topImage:nil]; + } +} + - (void)setupViewWithLabelAndImage:(NSString *)imageURL topImage:(NSString *)topImageString { UIView *centerView = [MVMCoreUICommonViewsUtility commonView]; diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift index 5b4cd3b7..99573688 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift @@ -8,61 +8,7 @@ import Foundation -public extension MVMCoreTopAlertObject { - static func create(with model: TopNotificationModel) -> Self { - let object = self.init() - object.persistent = model.persistent - object.type = model.type - object.topAlertDismissTime = model.dismissTime - object.queuePriority = model.priority - object.useNewStyle = true - object.json = model.toJSON() - return object - } -} - -public extension MVMCoreAlertHandler { - - /// Decodes the top alert json to a model. - static func decode(json: [AnyHashable: Any], delegateObject: MVMCoreUIDelegateObject?) throws -> TopNotificationModel { - let data = try JSONSerialization.data(withJSONObject: json) - let decoder = JSONDecoder() - if let delegateObject = delegateObject { - try decoder.add(delegateObject: delegateObject) - } - return try decoder.decode(TopNotificationModel.self, from: data) - } - - /// Shows the top alert with the json payload. - func showTopAlert(with json: [AnyHashable: Any], delegateObject: MVMCoreUIDelegateObject?) { - do { - let model = try Self.decode(json: json, delegateObject: delegateObject) - showTopAlert(with: model, delegateObject: delegateObject) - } catch { - if let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: "\(self)") { - MVMCoreUILoggingHandler.shared()?.addError(toLog: errorObject) - } - } - } - - /// Shows the top alert with the model. - func showTopAlert(with model: TopNotificationModel, delegateObject: MVMCoreUIDelegateObject?) { - let object = MVMCoreTopAlertObject.create(with: model) - guard let pages = model.pages else { - showTopAlert(with: object) - return - } - guard let controller = MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() as? MVMCoreViewControllerProtocol, - let pageType = controller.pageType, - pages.contains(pageType) else { - showTopAlert(with: object) - // add - return - } - showTopAlert(with: object) - } -} - +/// Allows top alerts to determine the status bar color and style. protocol StatusBarUI { func getStatusBarUI() -> (color: UIColor, style: UIStatusBarStyle) } @@ -87,24 +33,45 @@ public extension MVMCoreUITopAlertView { let model = TopNotificationModel(with: "Testing", molecule: molecule) model.persistent = false model.dismissTime = 10 + model.setPriority(with: 80) model.pages = nil//["settingsLanding"] jssoonnn?.updateValue(model.toJSON()!, forKey: "TopNotification")*/ guard let json = jssoonnn?.optionalDictionaryForKey("TopNotification") else { return } // TODO: Top alert view is current delegate. Should move to current view controller eventually? let delegateObject = MVMCoreUIDelegateObject.create(withDelegateForAll: self) - MVMCoreAlertHandler.shared()?.showTopAlert(with: json, delegateObject: delegateObject) + showTopAlert(with: json, delegateObject: delegateObject) } + /// When a detail page changes, check top alerts. @objc func viewControllerChanged(notification: Notification) { guard let controller = MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() as? MVMCoreViewControllerProtocol else { return } MVMCoreAlertHandler.shared()?.checkPagesDependency(for: controller.pageType) } + /// Shows the top alert with the json payload. + func showTopAlert(with json: [AnyHashable: Any], delegateObject: MVMCoreUIDelegateObject?) { + do { + let model = try TopNotificationModel.decode(json: json, delegateObject: delegateObject) + showTopAlert(with: model, delegateObject: delegateObject) + } catch { + if let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: "\(self)") { + MVMCoreUILoggingHandler.shared()?.addError(toLog: errorObject) + } + } + } + + /// Shows the top alert with the model. + func showTopAlert(with model: TopNotificationModel, delegateObject: MVMCoreUIDelegateObject?) { + let object = model.createTopAlertObject() + MVMCoreAlertHandler.shared()?.showTopAlert(with: object) + } + + /// Returns the top alert molecule to use and status bar color legacy style. @objc func molecule(for topAlertObject: MVMCoreTopAlertObject, statusBarColor: AutoreleasingUnsafeMutablePointer?, statusBarStyle: UnsafeMutablePointer?) -> MVMCoreUITopAlertBaseView? { do { let delegateObject = MVMCoreUIDelegateObject.create(withDelegateForAll: self) guard let json = topAlertObject.json else { return nil } - let model = try MVMCoreAlertHandler.decode(json: json, delegateObject: delegateObject) + let model = try TopNotificationModel.decode(json: json, delegateObject: delegateObject) guard let molecule = MoleculeObjectMapping.shared()?.createMolecule(model.molecule, delegateObject: delegateObject, additionalData: nil), let view = molecule as? MVMCoreUITopAlertBaseView else { throw ModelRegistry.Error.decoderOther(message: "Molecule not a top alert") @@ -122,131 +89,4 @@ public extension MVMCoreUITopAlertView { return nil } } - /* - /// Shows the top alert with the json payload. - func showTopAlert(with json: [AnyHashable: Any], delegateObject: MVMCoreUIDelegateObject?) { - /*do { - let model = try decode(json: json, delegateObject: delegateObject) - showTopAlert(with: model, delegateObject: delegateObject) - } catch { - if let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: "\(self)") { - MVMCoreUILoggingHandler.shared()?.addError(toLog: errorObject) - } - }*/ - } - - /// Shows the top alert with the model. - func showTopAlert(with model: TopNotificationModel, delegateObject: MVMCoreUIDelegateObject?) { - if let molecule = MoleculeObjectMapping.shared()?.createMolecule(model.molecule, delegateObject: delegateObject, additionalData: nil) { - - } - }*/ -} - -public class NotificationXButtonModel: Codable { - public var color: Color? - public var action: ActionModelProtocol? - - private enum CodingKeys: String, CodingKey { - case color - case action - } - - public init() { - } - - public required init(from decoder: Decoder) throws { - let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - color = try typeContainer.decodeIfPresent(Color.self, forKey: .color) - action = try typeContainer.decodeModelIfPresent(codingKey: .action) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encodeIfPresent(color, forKey: .color) - try container.encodeModelIfPresent(action, forKey: .action) - } -} - -public class NotificationModel: MoleculeModelProtocol { - public static var identifier: String = "notification" - public var moleculeName: String = NotificationModel.identifier - public var backgroundColor: Color? - public var headline: LabelModel - public var body: LabelModel? - public var button: ButtonModel? - public var closeButton: NotificationXButtonModel? - - init(with headline: LabelModel) { - self.headline = headline - } -} - -extension MVMCoreUITopAlertMainView: MoleculeViewProtocol { - public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { - guard let model = model as? NotificationModel else { return } - backgroundColor = model.backgroundColor?.uiColor ?? .mvmGreen - var actionMap = model.button?.action.toJSON() - if let title = model.button?.title { - actionMap?.updateValue(title, forKey: KeyTitle) - } - setupCloseButton(model.closeButton != nil, animationDelegate: MVMCoreUITopAlertView.sharedGlobal()?.animationDelegate) - setup(withMessage: model.headline.text, subMessage: model.body?.text, color: model.headline.textColor?.uiColor ?? .white, actionMap: actionMap, additionalData: nil) - } -} - -public class CollapsableNotificationModel: MoleculeModelProtocol { - public static var identifier: String = "collapsableNotification" - public var moleculeName: String = CollapsableNotificationModel.identifier - public var backgroundColor: Color? - public var topLabel: LabelModel - //public var topAction: ActionModelProtocol? - public var headline: LabelModel - public var body: LabelModel? - public var button: ButtonModel? - public var closeButton: NotificationXButtonModel? - public var alwaysShowCollapsedLabel = false - public var collapseTime: Int = 5 - public var initiallyCollapsed = false - //public var pages: [NSString]? - - init(with topLabel: LabelModel, headline: LabelModel) { - self.topLabel = topLabel - self.headline = headline - } -} - -extension MVMCoreUITopAlertExpandableView: MoleculeViewProtocol { - public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { - guard let model = model as? CollapsableNotificationModel else { return } - backgroundColor = model.backgroundColor?.uiColor ?? .mvmGreen - collapseTime = model.collapseTime - onlyShowTopMessageWhenCollapsed = !model.alwaysShowCollapsedLabel - - var actionMap = model.button?.action.toJSON() - if let title = model.button?.title { - actionMap?.updateValue(title, forKey: KeyTitle) - } - buttonView?.setupCloseButton(model.closeButton != nil, animationDelegate: MVMCoreUITopAlertView.sharedGlobal()?.animationDelegate) - setTopMessage(model.topLabel.text, message: model.headline.text, subMessage: model.body?.text, contentColor: model.headline.textColor?.uiColor ?? .white, actionMap: actionMap, additionalData: nil) - expand(false) - //[MVMCoreUITopAlertBaseView addActionToButton:survivalMode.shortView.button actionMap:topAlertObject.buttonMap additionalData:topAlertObject.additionalData]; - // survivalMode.shortView.label.accessibilityTraits = UIAccessibilityTraitButton; - } -} - -extension MVMCoreUITopAlertExpandableView: StatusBarUI { - func getStatusBarUI() -> (color: UIColor, style: UIStatusBarStyle) { - if shortView?.label?.text?.count ?? 0 > 0 { - let color = backgroundColor ?? UIColor.mvmGreen - var greyScale: CGFloat = 0 - if shortView?.label?.textColor.getWhite(&greyScale, alpha: nil) ?? false { - return (color, greyScale > 0.5 ? .lightContent : .default) - } else { - return (color, .default) - } - } else { - return (.white, .default) - } - } } diff --git a/MVMCoreUI/TopAlert/Atomic/TopNotificationModel.swift b/MVMCoreUI/TopAlert/TopNotificationModel.swift similarity index 60% rename from MVMCoreUI/TopAlert/Atomic/TopNotificationModel.swift rename to MVMCoreUI/TopAlert/TopNotificationModel.swift index d6900c85..7c07c980 100644 --- a/MVMCoreUI/TopAlert/Atomic/TopNotificationModel.swift +++ b/MVMCoreUI/TopAlert/TopNotificationModel.swift @@ -27,6 +27,55 @@ open class TopNotificationModel: Codable { case analyticsData } + //-------------------------------------------------- + // MARK: - Convenience Functions + //-------------------------------------------------- + + /// Set the priority using percent 0-100 + open func setPriority(with percent: Float) { + // The new scale + let scale = Operation.QueuePriority.veryHigh.rawValue - Operation.QueuePriority.veryLow.rawValue + + // Adjust the percent to the new scale + let scaledPercent = (percent / 100.0) * Float(scale) + + // Finish shifting. + priority = Operation.QueuePriority(rawValue: Operation.QueuePriority.veryLow.rawValue + Int(scaledPercent)) ?? .normal + } + + /// Gets the priority as a percent (0-100) + open func getPriorityPercent() -> Float { + // Shift the value + let shifted = Float(priority.rawValue - Operation.QueuePriority.veryLow.rawValue) + + // The current scale + let scale = Operation.QueuePriority.veryHigh.rawValue - Operation.QueuePriority.veryLow.rawValue + + // Adjust to percent + return (shifted / Float(scale)) * 100.0 + } + + open func createTopAlertObject() -> MVMCoreTopAlertObject { + let object = MVMCoreTopAlertObject() + object.persistent = persistent + object.type = type + object.topAlertDismissTime = dismissTime + object.queuePriority = priority + object.useNewStyle = true + object.json = toJSON() + return object + } + + /// Decodes the top alert json to a model. + public static func decode(json: [AnyHashable: Any], delegateObject: MVMCoreUIDelegateObject?) throws -> Self { + let data = try JSONSerialization.data(withJSONObject: json) + let decoder = JSONDecoder() + if let delegateObject = delegateObject { + try decoder.add(delegateObject: delegateObject) + } + return try decoder.decode(self, from: data) + } + //-------------------------------------------------- // MARK: - Initializer //-------------------------------------------------- @@ -50,9 +99,7 @@ open class TopNotificationModel: Codable { type = try typeContainer.decode(String.self, forKey: .type) molecule = try typeContainer.decodeModel(codingKey: .molecule) if let priorityPercent = try typeContainer.decodeIfPresent(Float.self, forKey: .priority) { - let scale = Operation.QueuePriority.veryHigh.rawValue - Operation.QueuePriority.veryLow.rawValue - let scaledPercent = (priorityPercent / 100.0) * Float(scale) - self.priority = Operation.QueuePriority(rawValue: Operation.QueuePriority.veryLow.rawValue + Int(scaledPercent)) ?? .normal + setPriority(with: priorityPercent) } if let persistent = try typeContainer.decodeIfPresent(Bool.self, forKey: .persistent) { self.persistent = persistent @@ -68,10 +115,7 @@ open class TopNotificationModel: Codable { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(type, forKey: .type) try container.encodeModel(molecule, forKey: .molecule) - - let scale = Operation.QueuePriority.veryHigh.rawValue - Operation.QueuePriority.veryLow.rawValue - let priorityPercent = Int((Float(priority.rawValue - Operation.QueuePriority.veryLow.rawValue) / Float(scale)) * 100.0) - try container.encode(priorityPercent, forKey: .priority) + try container.encode(getPriorityPercent(), forKey: .priority) try container.encode(persistent, forKey: .persistent) try container.encode(dismissTime, forKey: .dismissTime) try container.encodeIfPresent(pages, forKey: .pages) From 4e5639407e1aac82da2cf4fa106fc9d2e49413d7 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 15 Sep 2020 11:41:56 -0400 Subject: [PATCH 5/8] comments --- .../TopNotification/NotificationModel.swift | 23 +++++++++++++++++++ .../MVMCoreUITopAlertView+Extension.swift | 2 ++ 2 files changed, 25 insertions(+) create mode 100644 MVMCoreUI/Atomic/Molecules/TopNotification/NotificationModel.swift diff --git a/MVMCoreUI/Atomic/Molecules/TopNotification/NotificationModel.swift b/MVMCoreUI/Atomic/Molecules/TopNotification/NotificationModel.swift new file mode 100644 index 00000000..ac74abb6 --- /dev/null +++ b/MVMCoreUI/Atomic/Molecules/TopNotification/NotificationModel.swift @@ -0,0 +1,23 @@ +// +// NotificationModel.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 9/15/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public class NotificationModel: MoleculeModelProtocol { + public static var identifier: String = "notification" + public var moleculeName: String = NotificationModel.identifier + public var backgroundColor: Color? + public var headline: LabelModel + public var body: LabelModel? + public var button: ButtonModel? + public var closeButton: NotificationXButtonModel? + + init(with headline: LabelModel) { + self.headline = headline + } +} diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift index 99573688..d14d100f 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift @@ -37,6 +37,8 @@ public extension MVMCoreUITopAlertView { model.pages = nil//["settingsLanding"] jssoonnn?.updateValue(model.toJSON()!, forKey: "TopNotification")*/ guard let json = jssoonnn?.optionalDictionaryForKey("TopNotification") else { return } + print("TYTYT top alert new json \(json)") + // TODO: Top alert view is current delegate. Should move to current view controller eventually? let delegateObject = MVMCoreUIDelegateObject.create(withDelegateForAll: self) showTopAlert(with: json, delegateObject: delegateObject) From 83a5010f65a0afcdadce8ce268a7718c322f6dfd Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 15 Sep 2020 12:20:41 -0400 Subject: [PATCH 6/8] remove print statements --- .../MVMCoreUITopAlertView+Extension.swift | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift index d14d100f..027875e7 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift @@ -23,21 +23,8 @@ public extension MVMCoreUITopAlertView { /// Checks for new top alert json @objc func responseJSONUpdated(notification: Notification) { - var jssoonnn = (notification.userInfo?[String(describing: MVMCoreLoadObject.self)] as? MVMCoreLoadObject)?.responseJSON - /*let molecule = CollapsableNotificationModel(with: LabelModel(text: "Top"), headline: LabelModel(text: "Headline")) - //let molecule = NotificationModel(with: LabelModel(text: "Hello")) - molecule.backgroundColor = Color(uiColor: .mvmRed) - molecule.button = ButtonModel(with: "Hi", action: ActionCancelModel()) - molecule.body = LabelModel(text: "Sup") - molecule.closeButton = NotificationXButtonModel() - let model = TopNotificationModel(with: "Testing", molecule: molecule) - model.persistent = false - model.dismissTime = 10 - model.setPriority(with: 80) - model.pages = nil//["settingsLanding"] - jssoonnn?.updateValue(model.toJSON()!, forKey: "TopNotification")*/ - guard let json = jssoonnn?.optionalDictionaryForKey("TopNotification") else { return } - print("TYTYT top alert new json \(json)") + let responseJSON = (notification.userInfo?[String(describing: MVMCoreLoadObject.self)] as? MVMCoreLoadObject)?.responseJSON + guard let json = responseJSON?.optionalDictionaryForKey("TopNotification") else { return } // TODO: Top alert view is current delegate. Should move to current view controller eventually? let delegateObject = MVMCoreUIDelegateObject.create(withDelegateForAll: self) From 5407ec9cefad806252835db49bf5286e7fe1ae2b Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 15 Sep 2020 14:10:45 -0400 Subject: [PATCH 7/8] tab bar history --- .../HorizontalCombinationViews/TabBar.swift | 4 +++ .../Atomic/Protocols/TabBarProtocol.swift | 3 ++ .../BaseControllers/ViewController.swift | 34 ++++++++++++------- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TabBar.swift b/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TabBar.swift index 1cf06325..1ee7ee71 100644 --- a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TabBar.swift +++ b/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TabBar.swift @@ -99,6 +99,10 @@ import Foundation self.tabBar(self, didSelect: newSelectedItem) }) } + + public func currentTabIndex() -> Int { + return model.selectedTab + } } extension UITabBarItem: MFButtonProtocol { diff --git a/MVMCoreUI/Atomic/Protocols/TabBarProtocol.swift b/MVMCoreUI/Atomic/Protocols/TabBarProtocol.swift index 19c7e107..1ee147f7 100644 --- a/MVMCoreUI/Atomic/Protocols/TabBarProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/TabBarProtocol.swift @@ -17,4 +17,7 @@ import Foundation /// Should select the tab index. As if the user selected it. @objc func selectTab(at index: Int) + + /// Returns the current tab + @objc func currentTabIndex() -> Int } diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index 336d5da6..f0d6ab84 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -39,6 +39,9 @@ import UIKit public var selectedField: UIView? + // Stores the previous tab bar index. + public var tabBarIndex: Int? + /// Checks if the screen width has changed open func screenSizeChanged() -> Bool { return !MVMCoreGetterUtility.cgfequalwiththreshold(previousScreenSize.width, view.bounds.size.width, 0.1) @@ -318,13 +321,27 @@ import UIKit //-------------------------------------------------- open func updateTabBar() { - guard MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() == self, - let tabModel = pageModel as? TabPageModelProtocol else { return } + guard MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() == self else { return } MVMCoreUISplitViewController.main()?.tabBar?.delegateObject = delegateObjectIVar - if let index = tabModel.tabBarIndex { + + if let index = (pageModel as? TabPageModelProtocol)?.tabBarIndex { MVMCoreUISplitViewController.main()?.tabBar?.highlightTab(at: index) + } else if let index = loadObject?.requestParameters?.actionMap?["tabBarIndex"] as? Int { + MVMCoreUISplitViewController.main()?.tabBar?.highlightTab(at: index) + } else if let index = self.tabBarIndex { + MVMCoreUISplitViewController.main()?.tabBar?.highlightTab(at: index) + } else if let index = MVMCoreUISplitViewController.main()?.tabBar?.currentTabIndex() { + // Store current tab index for cases like back button. + self.tabBarIndex = index + } + + if let hidden = (pageModel as? TabPageModelProtocol)?.tabBarHidden { + MVMCoreUISplitViewController.main()?.updateTabBarShowing(!hidden) + } else if let hidden = loadObject?.requestParameters?.actionMap?["tabBarHidden"] as? Bool { + MVMCoreUISplitViewController.main()?.updateTabBarShowing(!hidden) + } else { + MVMCoreUISplitViewController.main()?.updateTabBarShowing(true) } - MVMCoreUISplitViewController.main()?.updateTabBarShowing(!tabModel.tabBarHidden) } //-------------------------------------------------- @@ -454,15 +471,6 @@ import UIKit loadObject?.requestParameters?.openSupportPanel ?? (loadObject?.systemParametersJSON?.boolForKey(KeyOpenSupport) ?? false) == true { MVMCoreUISession.sharedGlobal()?.splitViewController?.showRightPanel(animated: true) } - - // Selects the tab if needed. Page driven takes priority over action driven (see viewWillAppear) - if let tab: Int = loadObject?.requestParameters?.actionMap?["tabBarIndex"] as? Int, - error == nil, - loadObject?.pageJSON?["tabBarIndex"] == nil { - MVMCoreDispatchUtility.performBlock(onMainThread: { - MVMCoreUISplitViewController.main()?.tabBar?.highlightTab(at: tab) - }) - } } //-------------------------------------------------- From 80d15f84da99fd4bb414e0cbe3f1410c7ca84399 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 15 Sep 2020 15:15:10 -0400 Subject: [PATCH 8/8] review updates --- .../TopAlert/MVMCoreUITopAlertView+Extension.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift index 027875e7..e6df7178 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift @@ -23,8 +23,8 @@ public extension MVMCoreUITopAlertView { /// Checks for new top alert json @objc func responseJSONUpdated(notification: Notification) { - let responseJSON = (notification.userInfo?[String(describing: MVMCoreLoadObject.self)] as? MVMCoreLoadObject)?.responseJSON - guard let json = responseJSON?.optionalDictionaryForKey("TopNotification") else { return } + guard let responseJSON = (notification.userInfo?[String(describing: MVMCoreLoadObject.self)] as? MVMCoreLoadObject)?.responseJSON, + let json = responseJSON.optionalDictionaryForKey("TopNotification") else { return } // TODO: Top alert view is current delegate. Should move to current view controller eventually? let delegateObject = MVMCoreUIDelegateObject.create(withDelegateForAll: self) @@ -65,10 +65,10 @@ public extension MVMCoreUITopAlertView { let view = molecule as? MVMCoreUITopAlertBaseView else { throw ModelRegistry.Error.decoderOther(message: "Molecule not a top alert") } - if let casteView = view as? StatusBarUI { - let statusBarUI = casteView.getStatusBarUI() - statusBarColor?.pointee = statusBarUI.color - statusBarStyle?.pointee = statusBarUI.style + if let castView = view as? StatusBarUI { + let (color, style) = castView.getStatusBarUI() + statusBarColor?.pointee = color + statusBarStyle?.pointee = style } return view } catch {