From 14d2516263b0255a643130736f147248ee4d84a3 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Mon, 29 Mar 2021 15:18:37 -0400 Subject: [PATCH] Move to separate files for behavior logic decode molecule for headline in eyebrowheadlinebody behaviors have models and handlers now, not just one --- .../Views/Video/ScrollBehaviorForVideo.swift | 25 ++++++ .../Video/ScrollBehaviorForVideoModel.swift | 20 +++++ .../Atoms/Views/{ => Video}/Video.swift | 0 .../Views/{ => Video}/VideoDataManager.swift | 0 .../Atoms/Views/{ => Video}/VideoModel.swift | 57 ++---------- .../Views/Video/VisibleBehaviorForVideo.swift | 28 ++++++ .../Video/VisibleBehaviorForVideoModel.swift | 20 +++++ MVMCoreUI/Atomic/MoleculeObjectMapping.swift | 5 +- .../EyebrowHeadlineBodyLinkModel.swift | 4 +- .../MoleculeModelProtocol.swift | 14 +++ .../Atomic/Protocols/TemplateProtocol.swift | 9 +- .../Atomic/Templates/TemplateModel.swift | 2 +- .../MVMControllerModelProtocol.swift | 2 +- .../BaseControllers/ViewController.swift | 6 +- .../PageBehaviorHandlerModelProtocol.swift | 36 ++++++++ .../PageBehaviorHandlerProtocol.swift | 30 +++++++ .../Behaviors/PageBehaviorModelProtocol.swift | 35 ++++++++ .../Behaviors/PageBehaviorProtocol.swift | 34 +++++++ .../PageBehaviorProtocolRequirer.swift | 11 +++ .../PageScrolledClosureBehavior.swift | 33 ------- .../PageVisibilityClosureBehavior.swift | 40 --------- .../ScreenBrightnessModifierBehavior.swift | 90 ++++++++++--------- 22 files changed, 325 insertions(+), 176 deletions(-) create mode 100644 MVMCoreUI/Atomic/Atoms/Views/Video/ScrollBehaviorForVideo.swift create mode 100644 MVMCoreUI/Atomic/Atoms/Views/Video/ScrollBehaviorForVideoModel.swift rename MVMCoreUI/Atomic/Atoms/Views/{ => Video}/Video.swift (100%) rename MVMCoreUI/Atomic/Atoms/Views/{ => Video}/VideoDataManager.swift (100%) rename MVMCoreUI/Atomic/Atoms/Views/{ => Video}/VideoModel.swift (64%) create mode 100644 MVMCoreUI/Atomic/Atoms/Views/Video/VisibleBehaviorForVideo.swift create mode 100644 MVMCoreUI/Atomic/Atoms/Views/Video/VisibleBehaviorForVideoModel.swift create mode 100644 MVMCoreUI/Behaviors/PageBehaviorHandlerModelProtocol.swift create mode 100644 MVMCoreUI/Behaviors/PageBehaviorHandlerProtocol.swift create mode 100644 MVMCoreUI/Behaviors/PageBehaviorModelProtocol.swift create mode 100644 MVMCoreUI/Behaviors/PageBehaviorProtocol.swift create mode 100644 MVMCoreUI/Behaviors/PageBehaviorProtocolRequirer.swift delete mode 100644 MVMCoreUI/Behaviors/PageScrolledClosureBehavior.swift delete mode 100644 MVMCoreUI/Behaviors/PageVisibilityClosureBehavior.swift diff --git a/MVMCoreUI/Atomic/Atoms/Views/Video/ScrollBehaviorForVideo.swift b/MVMCoreUI/Atomic/Atoms/Views/Video/ScrollBehaviorForVideo.swift new file mode 100644 index 00000000..77487305 --- /dev/null +++ b/MVMCoreUI/Atomic/Atoms/Views/Video/ScrollBehaviorForVideo.swift @@ -0,0 +1,25 @@ +// +// ScrollBehaviorForVideo.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 3/29/21. +// Copyright © 2021 Verizon Wireless. All rights reserved. +// + +import Foundation + +open class ScrollBehaviorForVideo: PageScrolledBehavior { + var model: PageBehaviorModelProtocol + + required public init(model: PageBehaviorModelProtocol, delegateObject: MVMCoreUIDelegateObject?) { + self.model = model + } + + public func pageScrolled(scrollView: UIScrollView) { + // If visible to not visible, pause video. + // If not visible to visible, unpause if needed, add visible behavior + guard let model = (model as? VisibleBehaviorForVideoModel)?.videoModel, + let view = model.view else { return } + model.halted = !view.isVisible(in: scrollView) + } +} diff --git a/MVMCoreUI/Atomic/Atoms/Views/Video/ScrollBehaviorForVideoModel.swift b/MVMCoreUI/Atomic/Atoms/Views/Video/ScrollBehaviorForVideoModel.swift new file mode 100644 index 00000000..6e460c22 --- /dev/null +++ b/MVMCoreUI/Atomic/Atoms/Views/Video/ScrollBehaviorForVideoModel.swift @@ -0,0 +1,20 @@ +// +// ScrollBehaviorForVideoModel.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 3/29/21. +// Copyright © 2021 Verizon Wireless. All rights reserved. +// + +import Foundation + +open class ScrollBehaviorForVideoModel: PageBehaviorModelProtocol { + + public static var identifier: String = "visibleBehaviorForVideoModel" + public var shouldAllowMultipleInstances: Bool = true + public weak var videoModel: VideoModel? + + init(with videoModel: VideoModel) { + self.videoModel = videoModel + } +} diff --git a/MVMCoreUI/Atomic/Atoms/Views/Video.swift b/MVMCoreUI/Atomic/Atoms/Views/Video/Video.swift similarity index 100% rename from MVMCoreUI/Atomic/Atoms/Views/Video.swift rename to MVMCoreUI/Atomic/Atoms/Views/Video/Video.swift diff --git a/MVMCoreUI/Atomic/Atoms/Views/VideoDataManager.swift b/MVMCoreUI/Atomic/Atoms/Views/Video/VideoDataManager.swift similarity index 100% rename from MVMCoreUI/Atomic/Atoms/Views/VideoDataManager.swift rename to MVMCoreUI/Atomic/Atoms/Views/Video/VideoDataManager.swift diff --git a/MVMCoreUI/Atomic/Atoms/Views/VideoModel.swift b/MVMCoreUI/Atomic/Atoms/Views/Video/VideoModel.swift similarity index 64% rename from MVMCoreUI/Atomic/Atoms/Views/VideoModel.swift rename to MVMCoreUI/Atomic/Atoms/Views/Video/VideoModel.swift index 1d079599..472ab3de 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/VideoModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Video/VideoModel.swift @@ -8,7 +8,7 @@ import Foundation -open class VideoModel: MoleculeModelProtocol { +open class VideoModel: MoleculeModelProtocol, PageBehaviorProtocolRequirer { public static var identifier = "video" public var backgroundColor: Color? public var video: String @@ -39,8 +39,6 @@ open class VideoModel: MoleculeModelProtocol { /// Keeps a reference to the video data. public var videoDataManager: VideoDataManager - private weak var visibleBehavior: PageVisibilityClosureBehavior? - private weak var scrollBehavior: PageScrolledClosureBehavior? private var activeListener: Any? private var resignActiveListener: Any? @@ -81,61 +79,16 @@ open class VideoModel: MoleculeModelProtocol { try container.encode(alwaysReset, forKey: .alwaysReset) } + public func getRequiredBehaviors() -> [PageBehaviorModelProtocol] { + return [VisibleBehaviorForVideoModel(with: self), ScrollBehaviorForVideoModel(with: self)] + } + open func addVisibilityHalting(for view: Video, delegateObject: MVMCoreUIDelegateObject?) { self.view = view halted = false - addVisibleBehavior(for: view, delegateObject: delegateObject) - addScrollBehavior(for: view, delegateObject: delegateObject) addActiveListener(for: view, delegateObject: delegateObject) } - /// Adds a behavior to pause the video on page hidden behavior and unpause if necessary on page shown. - open func addVisibleBehavior(for view: Video, delegateObject: MVMCoreUIDelegateObject?) { - - let onShow = { [weak self] in - guard let self = self, - let view = self.view, - view.isVisibleInDelegate() else { return } - self.halted = false - } - let onHide: () -> Void = { [weak self] in - self?.halted = true - } - - guard visibleBehavior == nil else { - visibleBehavior?.pageShownHandler = onShow - visibleBehavior?.pageHiddenHandler = onHide - return - } - - guard var delegate = delegateObject?.behaviorTemplateDelegate else { return } - let pauseBehavior = PageVisibilityClosureBehavior(with: onShow, onPageHiddenHandler: onHide) - delegate.add(behavior: pauseBehavior) - self.visibleBehavior = pauseBehavior - } - - /// Adds a behavior to pause the video if scrolled off of the page and unpause if necessary if scrolled on. - open func addScrollBehavior(for view: Video, delegateObject: MVMCoreUIDelegateObject?) { - - let onScroll = { [weak self] (scrollView: UIScrollView) in - // If visible to not visible, pause video. - // If not visible to visible, unpause if needed, add visible behavior - guard let self = self, - let view = self.view else { return } - self.halted = !view.isVisible(in: scrollView) - } - - guard scrollBehavior == nil else { - scrollBehavior?.pageScrolledHandler = onScroll - return - } - - guard var delegate = delegateObject?.behaviorTemplateDelegate else { return } - let scrollBehavior = PageScrolledClosureBehavior(with: onScroll) - delegate.add(behavior: scrollBehavior) - self.scrollBehavior = scrollBehavior - } - open func addActiveListener(for view: Video, delegateObject: MVMCoreUIDelegateObject?) { removeActiveListener() diff --git a/MVMCoreUI/Atomic/Atoms/Views/Video/VisibleBehaviorForVideo.swift b/MVMCoreUI/Atomic/Atoms/Views/Video/VisibleBehaviorForVideo.swift new file mode 100644 index 00000000..022585fd --- /dev/null +++ b/MVMCoreUI/Atomic/Atoms/Views/Video/VisibleBehaviorForVideo.swift @@ -0,0 +1,28 @@ +// +// VisibleBehaviorForVideo.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 3/29/21. +// Copyright © 2021 Verizon Wireless. All rights reserved. +// + +import Foundation + +open class VisibleBehaviorForVideo: PageVisibilityBehavior { + var model: PageBehaviorModelProtocol + + required public init(model: PageBehaviorModelProtocol, delegateObject: MVMCoreUIDelegateObject?) { + self.model = model + } + + public func onPageShown() { + guard let model = (model as? VisibleBehaviorForVideoModel)?.videoModel, + let view = model.view, + view.isVisibleInDelegate() else { return } + model.halted = false + } + + public func onPageHidden() { + (model as? VisibleBehaviorForVideoModel)?.videoModel?.halted = true + } +} diff --git a/MVMCoreUI/Atomic/Atoms/Views/Video/VisibleBehaviorForVideoModel.swift b/MVMCoreUI/Atomic/Atoms/Views/Video/VisibleBehaviorForVideoModel.swift new file mode 100644 index 00000000..45734dac --- /dev/null +++ b/MVMCoreUI/Atomic/Atoms/Views/Video/VisibleBehaviorForVideoModel.swift @@ -0,0 +1,20 @@ +// +// VisibleBehaviorForVideoModel.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 3/29/21. +// Copyright © 2021 Verizon Wireless. All rights reserved. +// + +import Foundation + +open class VisibleBehaviorForVideoModel: PageBehaviorModelProtocol { + + public static var identifier: String = "visibleBehaviorForVideoModel" + public var shouldAllowMultipleInstances: Bool = true + public weak var videoModel: VideoModel? + + init(with videoModel: VideoModel) { + self.videoModel = videoModel + } +} diff --git a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift index f868169d..13683ba3 100644 --- a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift +++ b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift @@ -243,6 +243,7 @@ import Foundation MoleculeObjectMapping.shared()?.register(viewClass: NotificationView.self, viewModelClass: NotificationModel.self) MoleculeObjectMapping.shared()?.register(viewClass: CollapsableNotification.self, viewModelClass: CollapsableNotificationModel.self) + // TODO: move all of these out of here. // MARK:- Helper models try? ModelRegistry.register(RuleRequiredModel.self) try? ModelRegistry.register(RuleAnyRequiredModel.self) @@ -261,7 +262,9 @@ import Foundation try? ModelRegistry.register(ActionTopNotificationModel.self) // MARK:- Behaviors - try? ModelRegistry.register(ScreenBrightnessModifierBehavior.self) + try? ModelRegistry.register(handler: ScreenBrightnessModifierBehavior.self, for: ScreenBrightnessModifierBehaviorModel.self) + try? ModelRegistry.register(handler: PageGetContactBehavior.self, for: PageGetContactBehaviorModel.self) + MoleculeObjectMapping.shared()?.register(viewClass: Label.self, viewModelClass: SwapMDNWithContactNameLabelModel.self) } /// Convenience function to get required modules for a give model diff --git a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLinkModel.swift b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLinkModel.swift index c9410775..2174514d 100644 --- a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLinkModel.swift +++ b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLinkModel.swift @@ -68,7 +68,7 @@ public class EyebrowHeadlineBodyLinkModel: MoleculeModelProtocol { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) eyebrow = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .eyebrow) - headline = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .headline) + headline = try typeContainer.decodeMoleculeIfPresent(codingKey: .headline) body = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .body) link = try typeContainer.decodeIfPresent(LinkModel.self, forKey: .link) setDefaults() @@ -83,7 +83,7 @@ public class EyebrowHeadlineBodyLinkModel: MoleculeModelProtocol { try container.encode(moleculeName, forKey: .moleculeName) try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) try container.encodeIfPresent(eyebrow, forKey: .eyebrow) - try container.encodeIfPresent(headline, forKey: .headline) + try container.encodeModelIfPresent(headline, forKey: .headline) try container.encodeIfPresent(body, forKey: .body) try container.encodeIfPresent(link, forKey: .link) } diff --git a/MVMCoreUI/Atomic/Protocols/ModelProtocols/MoleculeModelProtocol.swift b/MVMCoreUI/Atomic/Protocols/ModelProtocols/MoleculeModelProtocol.swift index a998b79d..1563c6bc 100644 --- a/MVMCoreUI/Atomic/Protocols/ModelProtocols/MoleculeModelProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/ModelProtocols/MoleculeModelProtocol.swift @@ -20,3 +20,17 @@ public extension MoleculeModelProtocol { static var categoryCodingKey: String { "moleculeName" } } + +extension KeyedDecodingContainer where Key: CodingKey { + /// Decodes to a registered molecule based on the identifier + public func decodeMoleculeIfPresent(codingKey: KeyedDecodingContainer.Key) throws -> T? { + + guard let model: MoleculeModelProtocol = try decodeModelIfPresent(codingKey: codingKey) else { return nil } + guard let modelT = model as? T else { + let message = "ModelRegistry Error wrong type: \(codingKey.stringValue)" + MVMCoreLoggingHandler.logDebugMessage(withDelegate: message) + throw ModelRegistry.Error.decoderOther(message: message) + } + return modelT + } +} diff --git a/MVMCoreUI/Atomic/Protocols/TemplateProtocol.swift b/MVMCoreUI/Atomic/Protocols/TemplateProtocol.swift index 04bc080b..6577b258 100644 --- a/MVMCoreUI/Atomic/Protocols/TemplateProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/TemplateProtocol.swift @@ -22,12 +22,15 @@ public extension TemplateProtocol where Self: ViewController { let data = try JSONSerialization.data(withJSONObject: pageJSON) let decoder = JSONDecoder() try decoder.add(delegateObject: delegateObjectIVar) - self.templateModel = try decodeTemplate(using: decoder, from: data) - self.model = templateModel as? MVMControllerModelProtocol + templateModel = try decodeTemplate(using: decoder, from: data) + model = templateModel as? MVMControllerModelProtocol + guard var model = model else { return } + model.traverseAndAdd(with: self) + var behaviorHandler = self + behaviorHandler.createBehaviors(for: model, delegateObject: delegateObjectIVar) } func decodeTemplate(using decoder: JSONDecoder, from data: Data) throws -> TemplateModel { return try decoder.decode(TemplateModel.self, from: data) } - } diff --git a/MVMCoreUI/Atomic/Templates/TemplateModel.swift b/MVMCoreUI/Atomic/Templates/TemplateModel.swift index bb8bb104..7c271021 100644 --- a/MVMCoreUI/Atomic/Templates/TemplateModel.swift +++ b/MVMCoreUI/Atomic/Templates/TemplateModel.swift @@ -29,7 +29,7 @@ import Foundation public var screenHeading: String? public var navigationBar: (NavigationItemModelProtocol & MoleculeModelProtocol)? public var formRules: [FormGroupRule]? - public var behaviors: [PageBehaviorProtocol]? + public var behaviors: [PageBehaviorModelProtocol]? public var tabBarHidden: Bool = false public var tabBarIndex: Int? diff --git a/MVMCoreUI/BaseControllers/MVMControllerModelProtocol.swift b/MVMCoreUI/BaseControllers/MVMControllerModelProtocol.swift index 64242fc3..78f6f604 100644 --- a/MVMCoreUI/BaseControllers/MVMControllerModelProtocol.swift +++ b/MVMCoreUI/BaseControllers/MVMControllerModelProtocol.swift @@ -9,6 +9,6 @@ import Foundation -public protocol MVMControllerModelProtocol: TemplateModelProtocol, FormHolderModelProtocol, PageBehaviorsTemplateProtocol { +public protocol MVMControllerModelProtocol: TemplateModelProtocol, FormHolderModelProtocol, PageBehaviorHandlerModelProtocol { } diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index a2d82952..b841a062 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -8,7 +8,7 @@ import UIKit -@objc open class ViewController: UIViewController, MVMCoreViewControllerProtocol, MVMCoreViewManagerViewControllerProtocol, MoleculeDelegateProtocol, FormHolderProtocol, MVMCoreActionDelegateProtocol, MVMCoreLoadDelegateProtocol, UITextFieldDelegate, UITextViewDelegate, ObservingTextFieldDelegate, MVMCoreUIDetailViewProtocol, PageProtocol { +@objc open class ViewController: UIViewController, MVMCoreViewControllerProtocol, MVMCoreViewManagerViewControllerProtocol, MoleculeDelegateProtocol, FormHolderProtocol, MVMCoreActionDelegateProtocol, MVMCoreLoadDelegateProtocol, UITextFieldDelegate, UITextViewDelegate, ObservingTextFieldDelegate, MVMCoreUIDetailViewProtocol, PageProtocol, PageBehaviorHandlerProtocol { //-------------------------------------------------- // MARK: - Properties @@ -34,6 +34,8 @@ import UIKit public var formValidator: FormValidator? + public var behaviors: [PageBehaviorProtocol]? + public var needsUpdateUI = false private var observingForResponses = false private var initialLoadFinished = false @@ -620,6 +622,6 @@ import UIKit //-------------------------------------------------- func executeBehaviors(_ behaviorBlock:(_ behavior:T)->Void) { - model?.behaviors?.compactMap { $0 as? T }.forEach { behaviorBlock($0) } + behaviors?.compactMap { $0 as? T }.forEach { behaviorBlock($0) } } } diff --git a/MVMCoreUI/Behaviors/PageBehaviorHandlerModelProtocol.swift b/MVMCoreUI/Behaviors/PageBehaviorHandlerModelProtocol.swift new file mode 100644 index 00000000..d156d366 --- /dev/null +++ b/MVMCoreUI/Behaviors/PageBehaviorHandlerModelProtocol.swift @@ -0,0 +1,36 @@ +// +// PageBehaviorHandlerModelProtocol.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 3/29/21. +// Copyright © 2021 Verizon Wireless. All rights reserved. +// + +public protocol PageBehaviorHandlerModelProtocol { + var behaviors: [PageBehaviorModelProtocol]? { get set } +} + +public extension PageBehaviorHandlerModelProtocol { + + /// Adds the behavior model to the behaviors if possible. + mutating func add(behavior: PageBehaviorModelProtocol) { + var newBehaviors = behaviors ?? [] + guard !behavior.shouldAllowMultipleInstances, + !newBehaviors.contains(where: { $0.behaviorName == behavior.behaviorName + }) else { return } + newBehaviors.append(behavior) + self.behaviors = newBehaviors + } + + /// Traverses all models and adds any required behavior models. + mutating func traverseAndAdd(with page: PageProtocol?) { + PageGetContactBehavior.traverse(with: page, closure: { (model) in + guard let behaviorRequirer = model as? PageBehaviorProtocolRequirer, + var pageModel = page?.pageModel as? PageBehaviorHandlerModelProtocol else { return } + for behavior in behaviorRequirer.getRequiredBehaviors() { + pageModel.add(behavior: behavior) + } + }) + } +} + diff --git a/MVMCoreUI/Behaviors/PageBehaviorHandlerProtocol.swift b/MVMCoreUI/Behaviors/PageBehaviorHandlerProtocol.swift new file mode 100644 index 00000000..b90ac1aa --- /dev/null +++ b/MVMCoreUI/Behaviors/PageBehaviorHandlerProtocol.swift @@ -0,0 +1,30 @@ +// +// PageBehaviorHandlerProtocol.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 3/29/21. +// Copyright © 2021 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol PageBehaviorHandlerProtocol { + var behaviors: [PageBehaviorProtocol]? { get set } +} + +public extension PageBehaviorHandlerProtocol { + /// Creates the behaviors and sets the variable. + mutating func createBehaviors(for model: PageBehaviorHandlerModelProtocol, delegateObject: MVMCoreUIDelegateObject?) { + guard let behaviorModels = model.behaviors else { + behaviors = nil + return + } + var behaviors: [PageBehaviorProtocol] = [] + for behaviorModel in behaviorModels { + guard let handlerType = ModelRegistry.getHandler(behaviorModel) as? PageBehaviorProtocol.Type else { continue } + let behavior = handlerType.init(model: behaviorModel, delegateObject: delegateObject) + behaviors.append(behavior) + } + self.behaviors = behaviors.count > 0 ? behaviors : nil + } +} diff --git a/MVMCoreUI/Behaviors/PageBehaviorModelProtocol.swift b/MVMCoreUI/Behaviors/PageBehaviorModelProtocol.swift new file mode 100644 index 00000000..d8502a7e --- /dev/null +++ b/MVMCoreUI/Behaviors/PageBehaviorModelProtocol.swift @@ -0,0 +1,35 @@ +// +// PageBehaviorModelProtocol.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 3/29/21. +// Copyright © 2021 Verizon Wireless. All rights reserved. +// + +public protocol PageBehaviorModelProtocol: ModelProtocol { + + /// The type of rule + var behaviorName: String { get } + + /// If the behavior should allow multiple instances + var shouldAllowMultipleInstances: Bool { get } +} + +public extension PageBehaviorModelProtocol { + + var behaviorName: String { + get { type(of:self).identifier } + } + + static var shouldAllowMultipleInstances: Bool { + get { true } + } + + static var categoryCodingKey: String { + "behaviorName" + } + + static var categoryName: String { + "\(PageBehaviorModelProtocol.self)" + } +} diff --git a/MVMCoreUI/Behaviors/PageBehaviorProtocol.swift b/MVMCoreUI/Behaviors/PageBehaviorProtocol.swift new file mode 100644 index 00000000..2a3e9d28 --- /dev/null +++ b/MVMCoreUI/Behaviors/PageBehaviorProtocol.swift @@ -0,0 +1,34 @@ +// +// PageBehaviorProtocol.swift +// MVMCoreUI +// +// Created by Kyle on 5/8/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol PageBehaviorProtocol: ModelHandlerProtocol { + + /// Initializes the behavior with the model + init(model: PageBehaviorModelProtocol, delegateObject: MVMCoreUIDelegateObject?) +} + +public protocol PageVisibilityBehavior: PageBehaviorProtocol { + + func onPageShown() + func onPageHidden() +} + +public protocol PageScrolledBehavior: PageBehaviorProtocol { + + func pageScrolled(scrollView: UIScrollView) +} + +public extension MVMCoreUIDelegateObject { + weak var behaviorTemplateDelegate: (PageBehaviorHandlerProtocol & NSObjectProtocol)? { + get { + return (moleculeDelegate as? PageProtocol)?.pageModel as? (PageBehaviorHandlerProtocol & NSObjectProtocol) + } + } +} diff --git a/MVMCoreUI/Behaviors/PageBehaviorProtocolRequirer.swift b/MVMCoreUI/Behaviors/PageBehaviorProtocolRequirer.swift new file mode 100644 index 00000000..9ca72e1d --- /dev/null +++ b/MVMCoreUI/Behaviors/PageBehaviorProtocolRequirer.swift @@ -0,0 +1,11 @@ +// +// PageBehaviorProtocolRequirer.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 3/29/21. +// Copyright © 2021 Verizon Wireless. All rights reserved. +// + +public protocol PageBehaviorProtocolRequirer { + func getRequiredBehaviors() -> [PageBehaviorModelProtocol] +} diff --git a/MVMCoreUI/Behaviors/PageScrolledClosureBehavior.swift b/MVMCoreUI/Behaviors/PageScrolledClosureBehavior.swift deleted file mode 100644 index c43d4ecc..00000000 --- a/MVMCoreUI/Behaviors/PageScrolledClosureBehavior.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// PageScrolledClosureBehavior.swift -// MVMCoreUI -// -// Created by Scott Pfeil on 2/11/21. -// Copyright © 2021 Verizon Wireless. All rights reserved. -// - -import Foundation - -public class PageScrolledClosureBehavior: PageScrolledBehavior { - - public static var identifier = "pageScrolledClosureBehavior" - - public var pageScrolledHandler: (_ scrollView: UIScrollView) -> Void - - public init(with onPageScrolledHandler: @escaping (_ scrollView: UIScrollView) -> Void) { - self.pageScrolledHandler = onPageScrolledHandler - } - - // This class is not meant to be decoded and encoded really. - public required init(from decoder: Decoder) throws { - throw ModelRegistry.Error.decoderOther(message: "PageScrolledClosureBehavior does not decode.") - } - - public func encode(to encoder: Encoder) throws { - throw ModelRegistry.Error.decoderOther(message: "PageScrolledClosureBehavior does not encode.") - } - - public func pageScrolled(scrollView: UIScrollView) { - pageScrolledHandler(scrollView) - } -} diff --git a/MVMCoreUI/Behaviors/PageVisibilityClosureBehavior.swift b/MVMCoreUI/Behaviors/PageVisibilityClosureBehavior.swift deleted file mode 100644 index f5ecd82c..00000000 --- a/MVMCoreUI/Behaviors/PageVisibilityClosureBehavior.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// PageVisibilityClosureBehavior.swift -// MVMCoreUI -// -// Created by Scott Pfeil on 2/11/21. -// Copyright © 2021 Verizon Wireless. All rights reserved. -// - -import Foundation - -public class PageVisibilityClosureBehavior: PageVisibilityBehavior { - - public static var identifier = "pageVisibilityClosureBehavior" - - public var pageShownHandler: () -> Void - public var pageHiddenHandler: () -> Void - - public init(with onPageShownHandler: @escaping () -> Void, onPageHiddenHandler: @escaping () -> Void) { - self.pageShownHandler = onPageShownHandler - self.pageHiddenHandler = onPageHiddenHandler - } - - // This class is not meant to be decoded and encoded really. - public required init(from decoder: Decoder) throws { - throw ModelRegistry.Error.decoderOther(message: "PageVisibilityClosureBehavior does not decode.") - } - - public func encode(to encoder: Encoder) throws { - throw ModelRegistry.Error.decoderOther(message: "PageVisibilityClosureBehavior does not encode.") - } - - //MARK:- PageVisibilityBehavior - public func onPageShown() { - pageShownHandler() - } - - public func onPageHidden() { - pageHiddenHandler() - } -} diff --git a/MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift b/MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift index b6ea9f6d..30a5b035 100644 --- a/MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift +++ b/MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift @@ -6,52 +6,14 @@ // Copyright © 2020 Verizon Wireless. All rights reserved. // -public class ScreenBrightnessModifierBehavior: PageVisibilityBehavior { - +public class ScreenBrightnessModifierBehaviorModel: PageBehaviorModelProtocol { + public var shouldAllowMultipleInstances: Bool = false public static var identifier = "screenBrightnessModifier" - @Clamping(range: 0...1) var screenBrightness: CGFloat - var originalScreenBrightness: CGFloat? - //MARK:- PageVisibilityBehavior - - public func onPageShown() { - changeScreenBrightness() - } - - public func onPageHidden() { - restoreScreenBrightness() - } - - //MARK:- Behavior - - func changeScreenBrightness() { - guard originalScreenBrightness == nil else { return } - originalScreenBrightness = UIScreen.main.brightness - UIScreen.main.brightness = screenBrightness - NotificationCenter.default.addObserver(self, selector: #selector(willResignActive), name: UIApplication.willResignActiveNotification, object: nil) - } - - func restoreScreenBrightness() { - guard let originalScreenBrightness = originalScreenBrightness else { return } - UIScreen.main.brightness = originalScreenBrightness - self.originalScreenBrightness = nil - NotificationCenter.default.removeObserver(self, name: UIApplication.willResignActiveNotification, object: nil) - } - - @objc func willResignActive() { - restoreScreenBrightness() - NotificationCenter.default.addObserver(self, selector: #selector(didBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil) - } - - @objc func didBecomeActive() { - NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil) - changeScreenBrightness() - } - //MARK:- Codable - + private enum CodingKeys: String, CodingKey { case screenBrightness } @@ -66,3 +28,49 @@ public class ScreenBrightnessModifierBehavior: PageVisibilityBehavior { try container.encode(screenBrightness, forKey: .screenBrightness) } } + +public class ScreenBrightnessModifierBehavior: PageVisibilityBehavior { + var model: PageBehaviorModelProtocol + + required public init(model: PageBehaviorModelProtocol, delegateObject: MVMCoreUIDelegateObject?) { + self.model = model + } + + //MARK:- PageVisibilityBehavior + + public func onPageShown() { + changeScreenBrightness() + } + + public func onPageHidden() { + restoreScreenBrightness() + } + + //MARK:- Behavior + + func changeScreenBrightness() { + guard let model = model as? ScreenBrightnessModifierBehaviorModel, + model.originalScreenBrightness == nil else { return } + model.originalScreenBrightness = UIScreen.main.brightness + UIScreen.main.brightness = model.screenBrightness + NotificationCenter.default.addObserver(self, selector: #selector(willResignActive), name: UIApplication.willResignActiveNotification, object: nil) + } + + func restoreScreenBrightness() { + guard let model = model as? ScreenBrightnessModifierBehaviorModel, + let originalScreenBrightness = model.originalScreenBrightness else { return } + UIScreen.main.brightness = originalScreenBrightness + model.originalScreenBrightness = nil + NotificationCenter.default.removeObserver(self, name: UIApplication.willResignActiveNotification, object: nil) + } + + @objc func willResignActive() { + restoreScreenBrightness() + NotificationCenter.default.addObserver(self, selector: #selector(didBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil) + } + + @objc func didBecomeActive() { + NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil) + changeScreenBrightness() + } +}