From 81c099d5f9a813f52b67cd7080e40b9106d9542d Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 31 Mar 2021 11:08:56 -0400 Subject: [PATCH 01/44] length check for attrivutes --- MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift index e8c8446f..c24c880e 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift @@ -828,7 +828,10 @@ extension Label { private func addActionAttributes(range: NSRange, string: NSMutableAttributedString?) { - guard let string = string else { return } + guard let string = string, + string.length >= range.length + else { return } + string.addAttributes([NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue], range: range) } From 5297ed5ec0afb380ad772a8739ac22c59fed6d29 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 31 Mar 2021 11:13:57 -0400 Subject: [PATCH 02/44] undo --- MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift index c24c880e..b8300459 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift @@ -828,9 +828,7 @@ extension Label { private func addActionAttributes(range: NSRange, string: NSMutableAttributedString?) { - guard let string = string, - string.length >= range.length - else { return } + guard let string = string else { return } string.addAttributes([NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue], range: range) } From 06a42cfa21d4ffb1f0c6f8462f35fe2d834b8f5b Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 13 Apr 2021 15:07:44 -0400 Subject: [PATCH 03/44] audio behavior --- MVMCoreUI.xcodeproj/project.pbxproj | 4 ++ MVMCoreUI/Behaviors/PlayAudioBehavior.swift | 54 +++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 MVMCoreUI/Behaviors/PlayAudioBehavior.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index cb13de6f..fc435de1 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -61,6 +61,7 @@ 01EB369323609801006832FA /* HeaderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368C23609801006832FA /* HeaderModel.swift */; }; 01EB369423609801006832FA /* HeadlineBodyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368D23609801006832FA /* HeadlineBodyModel.swift */; }; 01F2A03223A4498200D954D8 /* CaretLinkModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2A03123A4498200D954D8 /* CaretLinkModel.swift */; }; + 0A01DE272626236300C2CAAC /* PlayAudioBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A01DE262626236300C2CAAC /* PlayAudioBehavior.swift */; }; 0A0FEC7425D42A5E00AF2548 /* BaseItemPickerEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A0FEC7325D42A5E00AF2548 /* BaseItemPickerEntryField.swift */; }; 0A0FEC7825D42A8500AF2548 /* BaseItemPickerEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A0FEC7725D42A8500AF2548 /* BaseItemPickerEntryFieldModel.swift */; }; 0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */; }; @@ -622,6 +623,7 @@ 01EB368C23609801006832FA /* HeaderModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderModel.swift; sourceTree = ""; }; 01EB368D23609801006832FA /* HeadlineBodyModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeadlineBodyModel.swift; sourceTree = ""; }; 01F2A03123A4498200D954D8 /* CaretLinkModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaretLinkModel.swift; sourceTree = ""; }; + 0A01DE262626236300C2CAAC /* PlayAudioBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayAudioBehavior.swift; sourceTree = ""; }; 0A0FEC7325D42A5E00AF2548 /* BaseItemPickerEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseItemPickerEntryField.swift; sourceTree = ""; }; 0A0FEC7725D42A8500AF2548 /* BaseItemPickerEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseItemPickerEntryFieldModel.swift; sourceTree = ""; }; 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionDetailWithImage.swift; sourceTree = ""; }; @@ -1311,6 +1313,7 @@ 0A1C30972620F61A00B47F3B /* Protocols */, 27F97369246750BE00CAB5C5 /* ScreenBrightnessModifierBehavior.swift */, D23A900826125FFB007E14CE /* GetContactBehavior.swift */, + 0A01DE262626236300C2CAAC /* PlayAudioBehavior.swift */, ); path = Behaviors; sourceTree = ""; @@ -2878,6 +2881,7 @@ D2092355244FA0FD0044AD09 /* ThreeLayerTemplateModelProtocol.swift in Sources */, 0AE14F64238315D2005417F8 /* TextField.swift in Sources */, 0A51F3E22475CB73002E08B6 /* LoadingSpinnerModel.swift in Sources */, + 0A01DE272626236300C2CAAC /* PlayAudioBehavior.swift in Sources */, D2169303251E53D9002A6324 /* SectionListTemplateModel.swift in Sources */, 0AB764D124460F6300E7FE72 /* UIDatePicker+Extension.swift in Sources */, BB105859248DEFF70069D008 /* UICollectionViewLeftAlignedLayout.swift in Sources */, diff --git a/MVMCoreUI/Behaviors/PlayAudioBehavior.swift b/MVMCoreUI/Behaviors/PlayAudioBehavior.swift new file mode 100644 index 00000000..9b1e1ba9 --- /dev/null +++ b/MVMCoreUI/Behaviors/PlayAudioBehavior.swift @@ -0,0 +1,54 @@ +// +// PlayAudioBehavior.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 4/9/21. +// Copyright © 2021 Verizon Wireless. All rights reserved. +// + + +public protocol PagePlayAudioBehaviorConsumerProtocol { +// func getMatchParameters() -> (NSPredicate, [CNKeyDescriptor])? +// func consume(contacts: [CNContact]) +} + +public class PagePlayAudioBehaviorModel: PageBehaviorModelProtocol { + public class var identifier: String { "pagePlayAudioBehavior" } + public var shouldAllowMultipleInstances: Bool { false } + + public init() { } +} + +public class PagePlayAudioBehavior: PageVisibilityBehavior { + var delegate: MVMCoreUIDelegateObject? + + public required init(model: PageBehaviorModelProtocol, delegateObject: MVMCoreUIDelegateObject?) { + self.delegate = delegateObject + } + + public func onPageShown(_ delegateObject: MVMCoreUIDelegateObject?) { + // Ask for permission +// CNContactStore().requestAccess(for: .contacts) { [weak self] (access, error) in +// guard access, +// error == nil, +// // TODO: Clean up this interface +// let model = (self?.delegate?.moleculeDelegate as? PageProtocol)?.pageModel as? TemplateModelProtocol else { return } +// // Iterate models and provide contact +// let store = CNContactStore() +// let consumers: [PagePlayAudioBehaviorConsumerProtocol] = model.allMoleculesOfType() +// for consumer in consumers { +// guard let parameters = consumer.getMatchParameters(), +// let contacts = try? store.unifiedContacts(matching: parameters.0, keysToFetch: parameters.1) else { return } +// consumer.consume(contacts: contacts) +// } +// +// // Tell template to update +// MVMCoreDispatchUtility.performBlock(onMainThread: { +// // TODO: move to protocol function instead +// (self?.delegate?.moleculeDelegate as? ViewController)?.handleNewData() +// }) +// } + } + + public func onPageHidden(_ delegateObject: MVMCoreUIDelegateObject?) {} +} From 6b610638112f7b334d3665ed918c5cba22f5eee2 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 14 Apr 2021 11:23:14 -0400 Subject: [PATCH 04/44] Revising for play audio behavior. --- .../BaseControllers/ViewController.swift | 12 ++-- MVMCoreUI/Behaviors/GetContactBehavior.swift | 5 +- MVMCoreUI/Behaviors/PlayAudioBehavior.swift | 61 +++++++++++-------- .../OtherHandlers/CoreUIModelMapping.swift | 1 + 4 files changed, 47 insertions(+), 32 deletions(-) diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index 293bd49f..28fb37c5 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -475,10 +475,12 @@ import UIKit addFormParams(requestParameters) requestParameters.parentPageType = loadObject?.pageJSON?.optionalStringForKey("parentPageType") var pageForwardedData = additionalData ?? [:] + executeBehaviors { (behavior: PageLocalDataShareBehavior) in let dataMap = behavior.compileLocalPageDataForTransfer(delegateObjectIVar) - pageForwardedData.merge(dataMap) { (current, _) in current } + pageForwardedData.merge(dataMap) { current, _ in current } } + MVMCoreActionHandler.defaultHandleOpenPage(for: requestParameters, actionInformation: actionInformation, additionalData: pageForwardedData, delegateObject: delegateObject()) } @@ -486,14 +488,16 @@ import UIKit MVMCoreUILoggingHandler.shared()?.defaultLogAction(forController: self, actionInformation: actionInformation, additionalData: additionalData) } - open func handleUnknownActionType(_ actionType: String?, actionInformation: [AnyHashable : Any]?, additionalData: [AnyHashable : Any]?) { + open func handleUnknownActionType(_ actionType: String?, actionInformation: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) { var handled = false + executeBehaviors { (behavior: PageCustomActionHandlerBehavior) in - if (!handled) { + if !handled { handled = behavior.handleAction(type: actionType, information: actionInformation, additionalData: additionalData) } } - if (!handled) { + + if !handled { MVMCoreUIActionHandler.defaultHandleUnknownActionType(actionType, actionInformation: actionInformation, additionalData: additionalData, delegateObject: delegateObjectIVar) } } diff --git a/MVMCoreUI/Behaviors/GetContactBehavior.swift b/MVMCoreUI/Behaviors/GetContactBehavior.swift index 2c6205f2..d62e1ad0 100644 --- a/MVMCoreUI/Behaviors/GetContactBehavior.swift +++ b/MVMCoreUI/Behaviors/GetContactBehavior.swift @@ -9,6 +9,7 @@ import Foundation import Contacts + public protocol PageGetContactBehaviorConsumerProtocol { func getMatchParameters() -> (NSPredicate, [CNKeyDescriptor])? func consume(contacts: [CNContact]) @@ -18,7 +19,7 @@ public class PageGetContactBehaviorModel: PageBehaviorModelProtocol { public class var identifier: String { "pageGetContactBehavior" } public var shouldAllowMultipleInstances: Bool { false } - public init() {} + public init() { } } public class PageGetContactBehavior: PageVisibilityBehavior { @@ -51,5 +52,5 @@ public class PageGetContactBehavior: PageVisibilityBehavior { } } - public func onPageHidden(_ delegateObject: MVMCoreUIDelegateObject?) {} + public func onPageHidden(_ delegateObject: MVMCoreUIDelegateObject?) { } } diff --git a/MVMCoreUI/Behaviors/PlayAudioBehavior.swift b/MVMCoreUI/Behaviors/PlayAudioBehavior.swift index 9b1e1ba9..a9eebd55 100644 --- a/MVMCoreUI/Behaviors/PlayAudioBehavior.swift +++ b/MVMCoreUI/Behaviors/PlayAudioBehavior.swift @@ -8,8 +8,9 @@ public protocol PagePlayAudioBehaviorConsumerProtocol { -// func getMatchParameters() -> (NSPredicate, [CNKeyDescriptor])? -// func consume(contacts: [CNContact]) + func playPause() + func stop() + func isPlaying() } public class PagePlayAudioBehaviorModel: PageBehaviorModelProtocol { @@ -19,36 +20,44 @@ public class PagePlayAudioBehaviorModel: PageBehaviorModelProtocol { public init() { } } -public class PagePlayAudioBehavior: PageVisibilityBehavior { +public class PagePlayAudioBehavior: PageCustomActionHandlerBehavior { + //-------------------------------------------------- + // MARK: - Delegate + //-------------------------------------------------- + var delegate: MVMCoreUIDelegateObject? + //-------------------------------------------------- + // MARK: - Init + //-------------------------------------------------- + public required init(model: PageBehaviorModelProtocol, delegateObject: MVMCoreUIDelegateObject?) { self.delegate = delegateObject } - public func onPageShown(_ delegateObject: MVMCoreUIDelegateObject?) { - // Ask for permission -// CNContactStore().requestAccess(for: .contacts) { [weak self] (access, error) in -// guard access, -// error == nil, -// // TODO: Clean up this interface -// let model = (self?.delegate?.moleculeDelegate as? PageProtocol)?.pageModel as? TemplateModelProtocol else { return } -// // Iterate models and provide contact -// let store = CNContactStore() -// let consumers: [PagePlayAudioBehaviorConsumerProtocol] = model.allMoleculesOfType() -// for consumer in consumers { -// guard let parameters = consumer.getMatchParameters(), -// let contacts = try? store.unifiedContacts(matching: parameters.0, keysToFetch: parameters.1) else { return } -// consumer.consume(contacts: contacts) -// } -// -// // Tell template to update -// MVMCoreDispatchUtility.performBlock(onMainThread: { -// // TODO: move to protocol function instead -// (self?.delegate?.moleculeDelegate as? ViewController)?.handleNewData() -// }) -// } + //-------------------------------------------------- + // MARK: - Custom Action + //-------------------------------------------------- + + public func handleAction(type actionType: String?, information: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) -> Bool { + + let templateModel = (delegate?.moleculeDelegate as? PageProtocol)?.pageModel as? TemplateModelProtocol + + let consumers: [PagePlayAudioBehaviorConsumerProtocol] = templateModel!.allMoleculesOfType() + for consumer in consumers { + consumer.playPause() + } + + // Tell template to update. + MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in + // TODO: move to protocol function instead + (self?.delegate?.moleculeDelegate as? ViewController)?.handleNewData() + }) + + return true } - public func onPageHidden(_ delegateObject: MVMCoreUIDelegateObject?) {} + public func onPageHidden(_ delegateObject: MVMCoreUIDelegateObject?) { + // TODO: Stop player + } } diff --git a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift index 45d1b0c4..c77bb77e 100644 --- a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift +++ b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift @@ -224,6 +224,7 @@ open class CoreUIModelMapping: ModelMapping { open class func registerBehaviors() { try? ModelRegistry.register(handler: ScreenBrightnessModifierBehavior.self, for: ScreenBrightnessModifierBehaviorModel.self) try? ModelRegistry.register(handler: PageGetContactBehavior.self, for: PageGetContactBehaviorModel.self) + try? ModelRegistry.register(handler: PagePlayAudioBehavior.self, for: PagePlayAudioBehaviorModel.self) } open override class func registerActions() { From 4fea0eb473a9541b2ea2853ceffa1279d73db912 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 15 Apr 2021 16:54:34 -0400 Subject: [PATCH 05/44] adding play audio action. current implementation. --- .../MoleculeTreeTraversalProtocol.swift | 1 - MVMCoreUI/Behaviors/PlayAudioBehavior.swift | 149 ++++++++++++++++-- 2 files changed, 139 insertions(+), 11 deletions(-) diff --git a/MVMCoreUI/Atomic/Protocols/MoleculeTreeTraversalProtocol.swift b/MVMCoreUI/Atomic/Protocols/MoleculeTreeTraversalProtocol.swift index 4e7efabb..abe4cdd7 100644 --- a/MVMCoreUI/Atomic/Protocols/MoleculeTreeTraversalProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/MoleculeTreeTraversalProtocol.swift @@ -50,5 +50,4 @@ extension MoleculeTreeTraversalProtocol { return accumulator } } - } diff --git a/MVMCoreUI/Behaviors/PlayAudioBehavior.swift b/MVMCoreUI/Behaviors/PlayAudioBehavior.swift index a9eebd55..76d7e64b 100644 --- a/MVMCoreUI/Behaviors/PlayAudioBehavior.swift +++ b/MVMCoreUI/Behaviors/PlayAudioBehavior.swift @@ -8,9 +8,11 @@ public protocol PagePlayAudioBehaviorConsumerProtocol { - func playPause() + func togglePlayPause() + func play() + func pause() func stop() - func isPlaying() + var isPlaying: Bool { get } } public class PagePlayAudioBehaviorModel: PageBehaviorModelProtocol { @@ -21,6 +23,12 @@ public class PagePlayAudioBehaviorModel: PageBehaviorModelProtocol { } public class PagePlayAudioBehavior: PageCustomActionHandlerBehavior { + //-------------------------------------------------- + // MARK: - Active Model + //-------------------------------------------------- + + public static var activeAudioPlayer: PagePlayAudioBehaviorConsumerProtocol? + //-------------------------------------------------- // MARK: - Delegate //-------------------------------------------------- @@ -39,20 +47,33 @@ public class PagePlayAudioBehavior: PageCustomActionHandlerBehavior { // MARK: - Custom Action //-------------------------------------------------- + // Either play or pause public func handleAction(type actionType: String?, information: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) -> Bool { - let templateModel = (delegate?.moleculeDelegate as? PageProtocol)?.pageModel as? TemplateModelProtocol + // TODO: Has to grab the specific model that is active (expanded). Identify model holder of this action. - let consumers: [PagePlayAudioBehaviorConsumerProtocol] = templateModel!.allMoleculesOfType() - for consumer in consumers { - consumer.playPause() - } + // TODO: Update the model. play -> pause OR pause -> play + + // TODO: Download binary + + // TODO: Store audio file in cache using some key (messageID???) to store it. + + // TODO: Actually pause/play + + // TODO: Tell Template to update this cell (needs to be built). Currently it updates all cells. + +// let templateModel = (delegate?.moleculeDelegate as? PageProtocol)?.pageModel as? TemplateModelProtocol + Self.activeAudioPlayer?.play() +// let consumers: [PagePlayAudioBehaviorConsumerProtocol] = templateModel!.allMoleculesOfType() +// for consumer in consumers { +// consumer.playPause() +// } // Tell template to update. - MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in +// MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in // TODO: move to protocol function instead - (self?.delegate?.moleculeDelegate as? ViewController)?.handleNewData() - }) +// (self?.delegate?.moleculeDelegate as? ViewController)?.handleNewData() +// }) return true } @@ -60,4 +81,112 @@ public class PagePlayAudioBehavior: PageCustomActionHandlerBehavior { public func onPageHidden(_ delegateObject: MVMCoreUIDelegateObject?) { // TODO: Stop player } + + //-------------------------------------------------- + // MARK: - Download Audio File + //-------------------------------------------------- +/* + // https://oneconfluence.verizon.com/pages/viewpage.action?spaceKey=EIM&title=FDV+API + + /// The directory to store all downloaded voicemails. + func voicemailDirectory() -> URL? { + + guard let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return nil } + return documentsURL.appendingPathComponent("fios_vm") + } + + func voicemailListQuery(accountId: String, sourceIP: String, mdn: String, mailBoxNo: String, timeZone: String) { + + let url = URL(string: "")! + var request = URLRequest(url: url) + request.httpMethod = "POST" + + let task = URLSession.shared.dataTask(with: request) { data, response, error in + // do something with the result + // print(data) +// if let data = data { + // TODO: Receive List of MDNs + // if let data = data, let dataString = String(data: data, encoding: .utf8) { + // print("Response data string:\n \(dataString)") + // } + // print(String(data: data, encoding: .utf8)) +// } else { + // print("no data") +// } + } + + task.resume() + + } + + func fetchVoicemail(accountId: String, sourceIP: String, mdn: String, mailBoxNo: String) { + +// guard let messageID = messageID else { return } + + let url = URL(string: "")! + var request = URLRequest(url: url) + request.httpMethod = "POST" + + let task = URLSession.shared.dataTask(with: request) { data, response, error in + // do something with the result + // print(data) +// if let data = data { + //body/VoiceMailMessages/Stream/TN/VMID/Audio/bin + // TODO: Receive List of MDNs + // if let data = data, let dataString = String(data: data, encoding: .utf8) { + // print("Response data string:\n \(dataString)") + // } + // print(String(data: data, encoding: .utf8)) +// } else { + // print("no data") +// } + } + + task.resume() + + // TODO: Fetch Audio file. + } + + func downloadVoicemail(url: URL?) { + + let downloadTask = URLSession.shared.downloadTask(with: url!) { [weak self] url, response, error in + guard error == nil, + let fileURL = url + else { return } + + do { + // "data/user/0/com.verizon.myfios/files/VM_INBOX-8711.wav" + let documentsURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) + let savedURL = documentsURL.appendingPathComponent(fileURL.lastPathComponent) + try FileManager.default.moveItem(at: fileURL, to: savedURL) + self?.audioFilePath = savedURL + } catch let error as NSError { + MVMCoreLoggingHandler.logDebugMessage(withDelegate: error.debugDescription) + } + } + downloadTask.resume() + } + + func fetchAudioFilePath() { + + guard let messageID = messageID, // "INBOX-8711" + let cleanMDN = cleanMDN, // "4124712342" + let destinationURL = voicemailDirectory() + else { return } + + let uri = "com.verizon.fios.voice2/downloadvm?VM_DOWNLOAD_URI_DATA_MESSAGE_ID=\(messageID)&VM_DOWNLOAD_URI_DATA_TN=\(cleanMDN)" + let url = URL(string: uri) + + + // TODO: First check to see if the file is stored on disk, if not, then downloaded. + createDirectoryIfNeeded(url: destinationURL) + + if FileManager.default.fileExists(atPath: destinationURL.path) { + audioFilePath = destinationURL + + } else { + downloadVoicemail(url: url) + } + } + */ } From ac13ac60259d9e33e43c9bf5a07751de4e7a296e Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 19 Apr 2021 14:03:51 -0400 Subject: [PATCH 06/44] implementing a delegate pattern. --- MVMCoreUI/Behaviors/PlayAudioBehavior.swift | 59 ++++++++++++--------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/MVMCoreUI/Behaviors/PlayAudioBehavior.swift b/MVMCoreUI/Behaviors/PlayAudioBehavior.swift index 76d7e64b..572fac0b 100644 --- a/MVMCoreUI/Behaviors/PlayAudioBehavior.swift +++ b/MVMCoreUI/Behaviors/PlayAudioBehavior.swift @@ -13,6 +13,8 @@ public protocol PagePlayAudioBehaviorConsumerProtocol { func pause() func stop() var isPlaying: Bool { get } + var messageID: String? { get } + var audioFileURL: URL? { get set } } public class PagePlayAudioBehaviorModel: PageBehaviorModelProtocol { @@ -27,7 +29,7 @@ public class PagePlayAudioBehavior: PageCustomActionHandlerBehavior { // MARK: - Active Model //-------------------------------------------------- - public static var activeAudioPlayer: PagePlayAudioBehaviorConsumerProtocol? + public static var activeAudioPlayerDelegate: PagePlayAudioBehaviorConsumerProtocol? //-------------------------------------------------- // MARK: - Delegate @@ -50,31 +52,27 @@ public class PagePlayAudioBehavior: PageCustomActionHandlerBehavior { // Either play or pause public func handleAction(type actionType: String?, information: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) -> Bool { - // TODO: Has to grab the specific model that is active (expanded). Identify model holder of this action. - - // TODO: Update the model. play -> pause OR pause -> play - - // TODO: Download binary - - // TODO: Store audio file in cache using some key (messageID???) to store it. - - // TODO: Actually pause/play + // TODO: Impose Activity Indicator. + // Update the model. play -> pause OR pause -> play + if Self.activeAudioPlayerDelegate?.isPlaying ?? false { + Self.activeAudioPlayerDelegate?.pause() + + } else { + + // Download binary + downloadAudioFile { url in + + // TODO: Actually pause/play + Self.activeAudioPlayerDelegate?.audioFileURL = url + Self.activeAudioPlayerDelegate?.togglePlayPause() + + // TODO: Remove Activity Indicator. + } + } + // TODO: Tell Template to update this cell (needs to be built). Currently it updates all cells. - -// let templateModel = (delegate?.moleculeDelegate as? PageProtocol)?.pageModel as? TemplateModelProtocol - Self.activeAudioPlayer?.play() -// let consumers: [PagePlayAudioBehaviorConsumerProtocol] = templateModel!.allMoleculesOfType() -// for consumer in consumers { -// consumer.playPause() -// } - - // Tell template to update. -// MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in - // TODO: move to protocol function instead -// (self?.delegate?.moleculeDelegate as? ViewController)?.handleNewData() -// }) - + return true } @@ -85,6 +83,19 @@ public class PagePlayAudioBehavior: PageCustomActionHandlerBehavior { //-------------------------------------------------- // MARK: - Download Audio File //-------------------------------------------------- + + func downloadAudioFile(_ completion: @escaping (URL) -> ()) { + + // TODO: Check cache. Return if available +// let audioData = MVMCoreCache.shared()?.getCachedData(withName: PagePlayAudioBehavior.activeAudioPlayerDelegate!.messageID!) + + guard let soundFileURL = Bundle.main.url(forResource: "sampleAudio", withExtension: "wav") else { return } + + // TODO: Store audio file in cache using some key (messageID???) to store it. +// MVMCoreCache.shared()?.addData(toCache: soundFileURL.dataRepresentation, withName: PagePlayAudioBehavior.activeAudioPlayerDelegate!.messageID!) + completion(soundFileURL) +// return soundFileURL + } /* // https://oneconfluence.verizon.com/pages/viewpage.action?spaceKey=EIM&title=FDV+API From 6c51d3ee6570ef0623dc4e84102110f6cc8d12d0 Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Fri, 21 May 2021 16:37:23 +0530 Subject: [PATCH 07/44] Enabling downloading option for voicemails --- MVMCoreUI/Behaviors/PlayAudioBehavior.swift | 114 ++++++++++++++++++-- 1 file changed, 103 insertions(+), 11 deletions(-) diff --git a/MVMCoreUI/Behaviors/PlayAudioBehavior.swift b/MVMCoreUI/Behaviors/PlayAudioBehavior.swift index 572fac0b..4ba7aa9f 100644 --- a/MVMCoreUI/Behaviors/PlayAudioBehavior.swift +++ b/MVMCoreUI/Behaviors/PlayAudioBehavior.swift @@ -61,7 +61,7 @@ public class PagePlayAudioBehavior: PageCustomActionHandlerBehavior { } else { // Download binary - downloadAudioFile { url in + downloadAudioFile(information: information) { url in // TODO: Actually pause/play Self.activeAudioPlayerDelegate?.audioFileURL = url @@ -84,18 +84,110 @@ public class PagePlayAudioBehavior: PageCustomActionHandlerBehavior { // MARK: - Download Audio File //-------------------------------------------------- - func downloadAudioFile(_ completion: @escaping (URL) -> ()) { + func downloadAudioFile(information:[AnyHashable: Any]?,_ completion: @escaping (URL) -> ()) { + + guard let extraparams = information?["extraParameters"] as? [AnyHashable:Any] else {return} + guard let requestParams = MVMCoreRequestParameters.init(pageType: "getVoiceMailMessage", extraParameters: extraparams) else { return } - // TODO: Check cache. Return if available -// let audioData = MVMCoreCache.shared()?.getCachedData(withName: PagePlayAudioBehavior.activeAudioPlayerDelegate!.messageID!) - - guard let soundFileURL = Bundle.main.url(forResource: "sampleAudio", withExtension: "wav") else { return } - - // TODO: Store audio file in cache using some key (messageID???) to store it. -// MVMCoreCache.shared()?.addData(toCache: soundFileURL.dataRepresentation, withName: PagePlayAudioBehavior.activeAudioPlayerDelegate!.messageID!) - completion(soundFileURL) -// return soundFileURL + if let voicemailID = extraparams["messageID"] as? String, checkIfFileExists(voicemailID: voicemailID) { + let vmURL = self.constructVoicemailFilePathWithID(voicemailID: voicemailID) + completion(vmURL) + } else { + MVMCoreLoadHandler.sharedGlobal()?.sendRequest(requestParams, locationForError: "PlayAudioRequest", requestFinished: { response, error in + guard let voicemailJSON = response as? [String:AnyHashable] else { return } + guard let voicemail = voicemailJSON["bin"] as? String, let voicemailID = voicemailJSON["vmMessageId"] as? String else { return } + let audioURL = self.saveVoicemailToDocumentDirectory(voicemail: voicemail, voicemailID: voicemailID) + completion(audioURL) + }) + } } + + func checkIfFileExists(voicemailID:String) -> Bool { + var cachePath = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first + cachePath?.appendPathComponent("FiOS.FDV.Voicemails", isDirectory: false) + let fileName = cachePath?.appendingPathComponent("VM_\(voicemailID).wmv") + return FileManager.default.fileExists(atPath: fileName?.path ?? "") + } + + func constructVoicemailFilePathWithID(voicemailID:String) -> URL { + let voicemailUrl = URL(string: "fileNotFound")! + ///Setting Voicemail Path + var cachePath = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first + cachePath?.appendPathComponent("FiOS.FDV.Voicemails", isDirectory: false) + if let path = cachePath?.path, !FileManager.default.fileExists(atPath: path) { + do{ + try FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: false, attributes: nil) + } catch let error as NSError { + MVMCoreLoggingHandler.logDebugMessage(withDelegate: error.debugDescription) + } + } + let fileName = cachePath?.appendingPathComponent("VM_\(voicemailID).wmv") + return fileName ?? voicemailUrl + } + + func saveVoicemailToDocumentDirectory(voicemail:String, voicemailID:String) -> URL { + let voicemailUrl = URL(string: "fileNotFound")! + let fileName = self.constructVoicemailFilePathWithID(voicemailID: voicemailID) + let voicemailData = Data(base64Encoded: voicemail) + do{ + try voicemailData?.write(to: fileName, options: .completeFileProtection) + return fileName + } catch let error as NSError { + MVMCoreLoggingHandler.logDebugMessage(withDelegate: error.debugDescription) + } + return voicemailUrl + } + +// func saveVoicemailToDocumentDirectory(voicemail:String) -> URL { +// let voicemailUrl = URL(string: "fileNotFound")! +// ///Setting Voicemail Path +// +// let cacheDirectory = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first as NSString? +// +// if let cachePath = cacheDirectory?.appendingPathComponent("fdv.voicemails"), !FileManager.default.fileExists(atPath: cachePath) { +// do{ +// try FileManager.default.createDirectory(atPath: cachePath, withIntermediateDirectories: false, attributes: nil) +// } catch let error as NSError { +// MVMCoreLoggingHandler.logDebugMessage(withDelegate: error.debugDescription) +// } +// } +// let fileName = cacheDirectory?.appendingPathComponent("fdv.voicemails").appending("/VM_1.wmv") +//#warning("Pending task to check if we can protect the voicemail data") +// +// let voicemailData = Data(base64Encoded: voicemail) +// do{ +// if let _fileName = fileName, let fileUrl = URL(string: _fileName) { +// try voicemailData?.write(to: fileUrl, options: .completeFileProtection) +// return fileUrl +// } +// } catch let error as NSError { +// MVMCoreLoggingHandler.logDebugMessage(withDelegate: error.debugDescription) +// } +// return voicemailUrl +// } + + +// NSDictionary *completeProtection = [NSDictionary dictionaryWithObject:NSFileProtectionComplete forKey:NSFileProtectionKey]; +// [[NSFileManager defaultManager] setAttributes:completeProtection ofItemAtPath:appFile error:nil]; +// return ([data writeToFile:appFile atomically:YES]); + + +// func downloadVoicemail(url: URL?) { +// +// let downloadTask = URLSession.shared.downloadTask(with: url!) { url, response, error in +// guard error == nil, let fileURL = url else { return } +// do { +// let documentsURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) +// let savedURL = documentsURL.appendingPathComponent(fileURL.lastPathComponent) +// try FileManager.default.moveItem(at: fileURL, to: savedURL) +// +// } catch let error as NSError { +// MVMCoreLoggingHandler.logDebugMessage(withDelegate: error.debugDescription) +// } +// } +// downloadTask.resume() +// } + /* // https://oneconfluence.verizon.com/pages/viewpage.action?spaceKey=EIM&title=FDV+API From 00dc4c2a477e5f009d0ae7596c3a8670426b0bf5 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 8 Jun 2021 15:18:47 -0400 Subject: [PATCH 08/44] need to check action type --- MVMCoreUI/Behaviors/PlayAudioBehavior.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/MVMCoreUI/Behaviors/PlayAudioBehavior.swift b/MVMCoreUI/Behaviors/PlayAudioBehavior.swift index 4ba7aa9f..32dc9727 100644 --- a/MVMCoreUI/Behaviors/PlayAudioBehavior.swift +++ b/MVMCoreUI/Behaviors/PlayAudioBehavior.swift @@ -52,6 +52,7 @@ public class PagePlayAudioBehavior: PageCustomActionHandlerBehavior { // Either play or pause public func handleAction(type actionType: String?, information: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) -> Bool { + guard actionType == "playAudio" else { return false } // TODO: Impose Activity Indicator. // Update the model. play -> pause OR pause -> play From 97ecf292ddac6c52ea86839a38fea9c98c1e083b Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 17 Jun 2021 10:00:36 -0400 Subject: [PATCH 09/44] added new behaviors for select all boxes. --- MVMCoreUI.xcodeproj/project.pbxproj | 4 ++ .../Behaviors/SelectAllBoxesBehavior.swift | 60 +++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 6b5b0a14..5eedcf5b 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -108,6 +108,7 @@ 0A9D09222433796500D2E6C0 /* CarouselIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A9D091C2433796500D2E6C0 /* CarouselIndicator.swift */; }; 0AA33B3A2398524F0067DD0F /* Toggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AA33B392398524F0067DD0F /* Toggle.swift */; }; 0AA4D2E125CAEC72008DB32D /* AccessibilityModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AA4D2E025CAEC72008DB32D /* AccessibilityModelProtocol.swift */; }; + 0AAB7855267B86F900DD6437 /* SelectAllBoxesBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AAB7854267B86F900DD6437 /* SelectAllBoxesBehavior.swift */; }; 0AB000BA24BF63490090C5E7 /* ModalListPageTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB000B924BF63490090C5E7 /* ModalListPageTemplateModel.swift */; }; 0AB000BC24BF64A50090C5E7 /* ModalStackPageTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB000BB24BF64A50090C5E7 /* ModalStackPageTemplateModel.swift */; }; 0AB764D124460F6300E7FE72 /* UIDatePicker+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB764D024460F6300E7FE72 /* UIDatePicker+Extension.swift */; }; @@ -674,6 +675,7 @@ 0AA33B33239813C50067DD0F /* UIColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Extension.swift"; sourceTree = ""; }; 0AA33B392398524F0067DD0F /* Toggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toggle.swift; sourceTree = ""; }; 0AA4D2E025CAEC72008DB32D /* AccessibilityModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityModelProtocol.swift; sourceTree = ""; }; + 0AAB7854267B86F900DD6437 /* SelectAllBoxesBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectAllBoxesBehavior.swift; sourceTree = ""; }; 0AB000B924BF63490090C5E7 /* ModalListPageTemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalListPageTemplateModel.swift; sourceTree = ""; }; 0AB000BB24BF64A50090C5E7 /* ModalStackPageTemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalStackPageTemplateModel.swift; sourceTree = ""; }; 0AB764D024460F6300E7FE72 /* UIDatePicker+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDatePicker+Extension.swift"; sourceTree = ""; }; @@ -1316,6 +1318,7 @@ 27F97369246750BE00CAB5C5 /* ScreenBrightnessModifierBehavior.swift */, D23A900826125FFB007E14CE /* GetContactBehavior.swift */, 0A01DE262626236300C2CAAC /* PlayAudioBehavior.swift */, + 0AAB7854267B86F900DD6437 /* SelectAllBoxesBehavior.swift */, ); path = Behaviors; sourceTree = ""; @@ -2718,6 +2721,7 @@ 011D959B240451E3000E3791 /* RuleRequiredModel.swift in Sources */, 526A265C240D1FF700B0D828 /* ListTwoColumnCompareChangesModel.swift in Sources */, D2A92886241ACD99004E01C6 /* ProgrammaticTableViewController.swift in Sources */, + 0AAB7855267B86F900DD6437 /* SelectAllBoxesBehavior.swift in Sources */, BBAA4F05243D8E3B005AAD5F /* RadioBoxesModel.swift in Sources */, 01509D952327ED1900EF99AA /* HeadlineBodyLinkToggle.swift in Sources */, AA104ADA244734DB004D2810 /* HeadersH1LandingPageHeader.swift in Sources */, diff --git a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift new file mode 100644 index 00000000..70e5fdf0 --- /dev/null +++ b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift @@ -0,0 +1,60 @@ +// +// SelectAllBoxesBehavior.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 6/17/21. +// Copyright © 2021 Verizon Wireless. All rights reserved. +// + + +public class SelectAllBoxesBehaviorModel: PageBehaviorModelProtocol { + public class var identifier: String { "selectAllBoxesBehavior" } + public var shouldAllowMultipleInstances: Bool { false } + + public init() { } +} + +public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior { + //-------------------------------------------------- + // MARK: - Active Model + //-------------------------------------------------- + + //-------------------------------------------------- + // MARK: - Delegate + //-------------------------------------------------- + + var delegate: MVMCoreUIDelegateObject? + + //-------------------------------------------------- + // MARK: - Init + //-------------------------------------------------- + + public required init(model: PageBehaviorModelProtocol, delegateObject: MVMCoreUIDelegateObject?) { + self.delegate = delegateObject + } + + //-------------------------------------------------- + // MARK: - Custom Action + //-------------------------------------------------- + + // Either play or pause + public func handleAction(type actionType: String?, information: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) -> Bool { + + guard actionType == "selectAllBoxes" else { return false } + + // Update the model. play -> pause OR pause -> play + if true { + + } else { + + } + + // TODO: Tell Template to update this cell (needs to be built). Currently it updates all cells. + + return true + } + + public func onPageHidden(_ delegateObject: MVMCoreUIDelegateObject?) { + // TODO: Stop player + } +} From 975f3fa012a0e47652ce8982993968c75140dc4a Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 17 Jun 2021 16:54:25 -0400 Subject: [PATCH 10/44] select all behavior. --- .../Behaviors/SelectAllBoxesBehavior.swift | 29 ++++++++++++------- .../OtherHandlers/CoreUIModelMapping.swift | 1 + 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift index 70e5fdf0..66720d1e 100644 --- a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift +++ b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift @@ -10,10 +10,10 @@ public class SelectAllBoxesBehaviorModel: PageBehaviorModelProtocol { public class var identifier: String { "selectAllBoxesBehavior" } public var shouldAllowMultipleInstances: Bool { false } - public init() { } } + public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior { //-------------------------------------------------- // MARK: - Active Model @@ -42,19 +42,26 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior { guard actionType == "selectAllBoxes" else { return false } - // Update the model. play -> pause OR pause -> play - if true { - - } else { - - } - - // TODO: Tell Template to update this cell (needs to be built). Currently it updates all cells. + let currentVC = MVMCoreUIUtility.getCurrentVisibleController() + + + traverseAndSelectCheckboxes(view: currentVC.view) + + // TODO: A) select all boxes and the change the nav button title to "deselect all" + // TODO: B) deselect all boxes and change nav nutton title to "select all" return true } - public func onPageHidden(_ delegateObject: MVMCoreUIDelegateObject?) { - // TODO: Stop player + private func traverseAndSelectCheckboxes(view: UIView) { + + if let checkbox = view as? Checkbox { + checkbox.isSelected = true + return + } + + for subview in view.subviews { + traverseAndSelectCheckboxes(view: subview) + } } } diff --git a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift index c77bb77e..437b2e01 100644 --- a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift +++ b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift @@ -225,6 +225,7 @@ open class CoreUIModelMapping: ModelMapping { try? ModelRegistry.register(handler: ScreenBrightnessModifierBehavior.self, for: ScreenBrightnessModifierBehaviorModel.self) try? ModelRegistry.register(handler: PageGetContactBehavior.self, for: PageGetContactBehaviorModel.self) try? ModelRegistry.register(handler: PagePlayAudioBehavior.self, for: PagePlayAudioBehaviorModel.self) + try? ModelRegistry.register(handler: SelectAllBoxesBehavior.self, for: SelectAllBoxesBehaviorModel.self) } open override class func registerActions() { From b318474da1faca7ebda3cc7291fcfa1bb1a84876 Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Mon, 21 Jun 2021 22:33:39 +0530 Subject: [PATCH 11/44] Moving Downloading Audio file logic to view from Behaviour --- MVMCoreUI/Behaviors/PlayAudioBehavior.swift | 68 +-------------------- 1 file changed, 1 insertion(+), 67 deletions(-) diff --git a/MVMCoreUI/Behaviors/PlayAudioBehavior.swift b/MVMCoreUI/Behaviors/PlayAudioBehavior.swift index 32dc9727..7ea37809 100644 --- a/MVMCoreUI/Behaviors/PlayAudioBehavior.swift +++ b/MVMCoreUI/Behaviors/PlayAudioBehavior.swift @@ -60,16 +60,7 @@ public class PagePlayAudioBehavior: PageCustomActionHandlerBehavior { Self.activeAudioPlayerDelegate?.pause() } else { - - // Download binary - downloadAudioFile(information: information) { url in - - // TODO: Actually pause/play - Self.activeAudioPlayerDelegate?.audioFileURL = url - Self.activeAudioPlayerDelegate?.togglePlayPause() - - // TODO: Remove Activity Indicator. - } + Self.activeAudioPlayerDelegate?.play() } // TODO: Tell Template to update this cell (needs to be built). Currently it updates all cells. @@ -81,63 +72,6 @@ public class PagePlayAudioBehavior: PageCustomActionHandlerBehavior { // TODO: Stop player } - //-------------------------------------------------- - // MARK: - Download Audio File - //-------------------------------------------------- - - func downloadAudioFile(information:[AnyHashable: Any]?,_ completion: @escaping (URL) -> ()) { - - guard let extraparams = information?["extraParameters"] as? [AnyHashable:Any] else {return} - guard let requestParams = MVMCoreRequestParameters.init(pageType: "getVoiceMailMessage", extraParameters: extraparams) else { return } - - if let voicemailID = extraparams["messageID"] as? String, checkIfFileExists(voicemailID: voicemailID) { - let vmURL = self.constructVoicemailFilePathWithID(voicemailID: voicemailID) - completion(vmURL) - } else { - MVMCoreLoadHandler.sharedGlobal()?.sendRequest(requestParams, locationForError: "PlayAudioRequest", requestFinished: { response, error in - guard let voicemailJSON = response as? [String:AnyHashable] else { return } - guard let voicemail = voicemailJSON["bin"] as? String, let voicemailID = voicemailJSON["vmMessageId"] as? String else { return } - let audioURL = self.saveVoicemailToDocumentDirectory(voicemail: voicemail, voicemailID: voicemailID) - completion(audioURL) - }) - } - } - - func checkIfFileExists(voicemailID:String) -> Bool { - var cachePath = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first - cachePath?.appendPathComponent("FiOS.FDV.Voicemails", isDirectory: false) - let fileName = cachePath?.appendingPathComponent("VM_\(voicemailID).wmv") - return FileManager.default.fileExists(atPath: fileName?.path ?? "") - } - - func constructVoicemailFilePathWithID(voicemailID:String) -> URL { - let voicemailUrl = URL(string: "fileNotFound")! - ///Setting Voicemail Path - var cachePath = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first - cachePath?.appendPathComponent("FiOS.FDV.Voicemails", isDirectory: false) - if let path = cachePath?.path, !FileManager.default.fileExists(atPath: path) { - do{ - try FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: false, attributes: nil) - } catch let error as NSError { - MVMCoreLoggingHandler.logDebugMessage(withDelegate: error.debugDescription) - } - } - let fileName = cachePath?.appendingPathComponent("VM_\(voicemailID).wmv") - return fileName ?? voicemailUrl - } - - func saveVoicemailToDocumentDirectory(voicemail:String, voicemailID:String) -> URL { - let voicemailUrl = URL(string: "fileNotFound")! - let fileName = self.constructVoicemailFilePathWithID(voicemailID: voicemailID) - let voicemailData = Data(base64Encoded: voicemail) - do{ - try voicemailData?.write(to: fileName, options: .completeFileProtection) - return fileName - } catch let error as NSError { - MVMCoreLoggingHandler.logDebugMessage(withDelegate: error.debugDescription) - } - return voicemailUrl - } // func saveVoicemailToDocumentDirectory(voicemail:String) -> URL { // let voicemailUrl = URL(string: "fileNotFound")! From 76787545acb425929170bdfd94d64224789ae336 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 21 Jun 2021 14:07:37 -0400 Subject: [PATCH 12/44] Further development of the select all behavior. --- .../Atoms/Selectors/CheckboxModel.swift | 20 +++++-- .../Protocols/MoleculeDelegateProtocol.swift | 22 ++++--- .../BaseControllers/ViewController.swift | 2 +- .../Behaviors/SelectAllBoxesBehavior.swift | 57 ++++++++++++------- 4 files changed, 67 insertions(+), 34 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift index c2d9f14e..9ed1c849 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift @@ -6,10 +6,8 @@ // Copyright © 2020 Verizon Wireless. All rights reserved. // -import Foundation - -@objcMembers public class CheckboxModel: MoleculeModelProtocol, FormFieldProtocol { +@objcMembers public class CheckboxModel: MoleculeModelProtocol, SelectableModel, FormFieldProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -66,13 +64,25 @@ import Foundation case groupName case offAction } - + //-------------------------------------------------- - // MARK: - Methods + // MARK: - Form Validation //-------------------------------------------------- public func formFieldValue() -> AnyHashable? { checked } + //-------------------------------------------------- + // MARK: - Selectable Protocol + //-------------------------------------------------- + + public func select(as isSelected: Bool) { + checked = isSelected + } + + public var selectedValue: Bool { + checked + } + //-------------------------------------------------- // MARK: - Initializer //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Protocols/MoleculeDelegateProtocol.swift b/MVMCoreUI/Atomic/Protocols/MoleculeDelegateProtocol.swift index e61ea662..0435cf66 100644 --- a/MVMCoreUI/Atomic/Protocols/MoleculeDelegateProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/MoleculeDelegateProtocol.swift @@ -6,30 +6,34 @@ // Copyright © 2019 Verizon Wireless. All rights reserved. // -import Foundation public protocol MoleculeDelegateProtocol: AnyObject { - + func getRootMolecules() -> [MoleculeModelProtocol] /// returns a module for the corresponding module name. - func getModuleWithName(_ name: String?) -> [AnyHashable : Any]? + func getModuleWithName(_ name: String?) -> [AnyHashable: Any]? + func getModuleWithName(_ moleculeName: String) -> MoleculeModelProtocol? - + /// Notifies the delegate that the molecule layout update. Should be called when the layout may change due to an async method. Mainly used for list or collections. func moleculeLayoutUpdated(_ molecule: MoleculeViewProtocol) //optional - + /// Asks the delegate to add or remove molecules. Mainly used for list or collections. func getIndexPath(for molecule: ListItemModelProtocol & MoleculeModelProtocol) -> IndexPath? + func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], indexPath: IndexPath, animation: UITableView.RowAnimation) + func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], animation: UITableView.RowAnimation) } extension MoleculeDelegateProtocol { - public func moleculeLayoutUpdated(_ molecule: MoleculeViewProtocol) {} + public func moleculeLayoutUpdated(_ molecule: MoleculeViewProtocol) { } - public func getIndexPath(for molecule: ListItemModelProtocol & MoleculeModelProtocol) -> IndexPath? { return nil } - public func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], indexPath: IndexPath, animation: UITableView.RowAnimation) {} - public func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], animation: UITableView.RowAnimation) {} + public func getIndexPath(for molecule: ListItemModelProtocol & MoleculeModelProtocol) -> IndexPath? { nil } + + public func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], indexPath: IndexPath, animation: UITableView.RowAnimation) { } + + public func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], animation: UITableView.RowAnimation) { } } diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index 9745b3f4..06efad05 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -507,7 +507,7 @@ import UIKit //-------------------------------------------------- open func getRootMolecules() -> [MoleculeModelProtocol] { - return model?.rootMolecules ?? [] + model?.rootMolecules ?? [] } open func getModuleWithName(_ name: String?) -> [AnyHashable: Any]? { diff --git a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift index 66720d1e..a197a4d7 100644 --- a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift +++ b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift @@ -6,9 +6,13 @@ // Copyright © 2021 Verizon Wireless. All rights reserved. // +public protocol SelectableModel { + var selectedValue: Bool { get } + func select(as isSelected: Bool) +} public class SelectAllBoxesBehaviorModel: PageBehaviorModelProtocol { - public class var identifier: String { "selectAllBoxesBehavior" } + public class var identifier: String { "pageSelectAllBoxesBehavior" } public var shouldAllowMultipleInstances: Bool { false } public init() { } } @@ -16,9 +20,11 @@ public class SelectAllBoxesBehaviorModel: PageBehaviorModelProtocol { public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior { //-------------------------------------------------- - // MARK: - Active Model + // MARK: - Properties //-------------------------------------------------- + var didSelectAll = false + //-------------------------------------------------- // MARK: - Delegate //-------------------------------------------------- @@ -37,31 +43,44 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior { // MARK: - Custom Action //-------------------------------------------------- - // Either play or pause + // To select or deselect all controls adhereing to public func handleAction(type actionType: String?, information: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) -> Bool { - guard actionType == "selectAllBoxes" else { return false } + guard actionType == "selectAllBoxes", + let selectableModels: [SelectableModel] = delegate?.moleculeDelegate?.getRootMolecules().allMoleculesOfType(), + !selectableModels.isEmpty + else { return false } - let currentVC = MVMCoreUIUtility.getCurrentVisibleController() + didSelectAll.toggle() + let navButtonTitle: String? = (didSelectAll ? information!["deSelectAllTitle"] : information!["selectAllTitle"]) as? String - traverseAndSelectCheckboxes(view: currentVC.view) + for selectableModel in selectableModels { + if toSelect(model: selectableModel) || toDeselect(model: selectableModel) { + selectableModel.select(as: didSelectAll) + } + } + + MVMCoreDispatchUtility.performBlock(onMainThread: { + // TODO: move to protocol function instead + guard let controller = self.delegate?.moleculeDelegate as? ViewController else { return } + controller.handleNewDataAndUpdateUI() + + if MVMCoreUIUtility.getCurrentVisibleController() == controller { + // Update navigation bar if showing. + controller.navigationItem.rightBarButtonItem?.title = navButtonTitle + controller.manager?.refreshNavigationUI() + } + }) - // TODO: A) select all boxes and the change the nav button title to "deselect all" - // TODO: B) deselect all boxes and change nav nutton title to "select all" - return true } - private func traverseAndSelectCheckboxes(view: UIView) { - - if let checkbox = view as? Checkbox { - checkbox.isSelected = true - return - } - - for subview in view.subviews { - traverseAndSelectCheckboxes(view: subview) - } + func toSelect(model: SelectableModel) -> Bool { + didSelectAll && !model.selectedValue + } + + func toDeselect(model: SelectableModel) -> Bool { + !didSelectAll && model.selectedValue } } From cf8d0f967e1eed3c5649588f9d361400b7b56f0a Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 21 Jun 2021 15:27:22 -0400 Subject: [PATCH 13/44] move titles into behavior. changed selectable protocol name. --- .../Atoms/Selectors/CheckboxModel.swift | 2 +- .../Atomic/Atoms/Selectors/ToggleModel.swift | 16 +++- .../Behaviors/SelectAllBoxesBehavior.swift | 85 +++++++++++++++---- 3 files changed, 83 insertions(+), 20 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift index 9ed1c849..0b98d1fc 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift @@ -7,7 +7,7 @@ // -@objcMembers public class CheckboxModel: MoleculeModelProtocol, SelectableModel, FormFieldProtocol { +@objcMembers public class CheckboxModel: MoleculeModelProtocol, SelectableMoleculeModel, FormFieldProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift index 4990df73..e59a4738 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift @@ -7,7 +7,7 @@ // -public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableModelProtocol { +public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableModelProtocol, SelectableMoleculeModel { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -53,11 +53,23 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo } //-------------------------------------------------- - // MARK: - Methods + // MARK: - Form Valdiation //-------------------------------------------------- public func formFieldValue() -> AnyHashable? { state } + //-------------------------------------------------- + // MARK: - Selectable Protocol + //-------------------------------------------------- + + public func select(as isSelected: Bool) { + state = isSelected + } + + public var selectedValue: Bool { + state + } + //-------------------------------------------------- // MARK: - Initializer //-------------------------------------------------- diff --git a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift index a197a4d7..93d7367e 100644 --- a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift +++ b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift @@ -6,7 +6,10 @@ // Copyright © 2021 Verizon Wireless. All rights reserved. // -public protocol SelectableModel { +/// Protocol to apply to any model of a UI Control with a binary on/off nature. +/// +/// Example classes: Checkbox or Switch. +public protocol SelectableMoleculeModel { var selectedValue: Bool { get } func select(as isSelected: Bool) } @@ -14,16 +17,48 @@ public protocol SelectableModel { public class SelectAllBoxesBehaviorModel: PageBehaviorModelProtocol { public class var identifier: String { "pageSelectAllBoxesBehavior" } public var shouldAllowMultipleInstances: Bool { false } + public var selectAllTitle: String = "Select All" + public var deselectAllTitle: String = "Deselect All" public init() { } + + //-------------------------------------------------- + // MARK: - Codable + //-------------------------------------------------- + + private enum CodingKeys: String, CodingKey { + case selectAllTitle + case deselectAllTitle + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + + if let selectAllTitle = try typeContainer.decodeIfPresent(String.self, forKey: .selectAllTitle) { + self.selectAllTitle = selectAllTitle + } + + if let deselectAllTitle = try typeContainer.decodeIfPresent(String.self, forKey: .deselectAllTitle) { + self.deselectAllTitle = deselectAllTitle + } + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(selectAllTitle, forKey: .selectAllTitle) + try container.encode(deselectAllTitle, forKey: .deselectAllTitle) + } } - +/// Selects all the control models presented on a page. public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- - var didSelectAll = false + /// Status of the select all behavior. Initially false as the action has not been enaged. + var selectAllState = false + + var model: PageBehaviorModelProtocol //-------------------------------------------------- // MARK: - Delegate @@ -35,7 +70,8 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior { // MARK: - Init //-------------------------------------------------- - public required init(model: PageBehaviorModelProtocol, delegateObject: MVMCoreUIDelegateObject?) { + required public init(model: PageBehaviorModelProtocol, delegateObject: MVMCoreUIDelegateObject?) { + self.model = model self.delegate = delegateObject } @@ -43,31 +79,40 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior { // MARK: - Custom Action //-------------------------------------------------- - // To select or deselect all controls adhereing to + /// To select or deselect all controls adhereing to `SelectableMoleculeModel` + /// + /// - Parameters: + /// - actionType: The action type of the passed action model. + /// - information: information of the passed action model. + /// - additionalData: Additional information of the + /// - Returns: Boolean determines if the action has been handled. public func handleAction(type actionType: String?, information: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) -> Bool { + // Verify we have the correct action type and necessary values. guard actionType == "selectAllBoxes", - let selectableModels: [SelectableModel] = delegate?.moleculeDelegate?.getRootMolecules().allMoleculesOfType(), - !selectableModels.isEmpty + let selectableModels: [SelectableMoleculeModel] = delegate?.moleculeDelegate?.getRootMolecules().allMoleculesOfType(), + !selectableModels.isEmpty, + let model = model as? SelectAllBoxesBehaviorModel else { return false } - didSelectAll.toggle() - - let navButtonTitle: String? = (didSelectAll ? information!["deSelectAllTitle"] : information!["selectAllTitle"]) as? String + // Flip the selected state of the behavior. + selectAllState.toggle() + // Iterate through selectable molecules. for selectableModel in selectableModels { if toSelect(model: selectableModel) || toDeselect(model: selectableModel) { - selectableModel.select(as: didSelectAll) + selectableModel.select(as: selectAllState) } } + // Get title to update the nav button title. + let navButtonTitle: String? = selectAllState ? model.deselectAllTitle : model.selectAllTitle + MVMCoreDispatchUtility.performBlock(onMainThread: { - // TODO: move to protocol function instead guard let controller = self.delegate?.moleculeDelegate as? ViewController else { return } controller.handleNewDataAndUpdateUI() if MVMCoreUIUtility.getCurrentVisibleController() == controller { - // Update navigation bar if showing. controller.navigationItem.rightBarButtonItem?.title = navButtonTitle controller.manager?.refreshNavigationUI() } @@ -76,11 +121,17 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior { return true } - func toSelect(model: SelectableModel) -> Bool { - didSelectAll && !model.selectedValue + /// Convenience function making it easier to read if a current selectable model should be acted on. + /// - Parameter model: A model object assined to the SelectableModel protocol + /// - Returns: Boolean determining if the passed model should be selected. + func toSelect(model: SelectableMoleculeModel) -> Bool { + selectAllState && !model.selectedValue } - func toDeselect(model: SelectableModel) -> Bool { - !didSelectAll && model.selectedValue + /// Convenience function making it easier to read if a current selectable model should be acted on. + /// - Parameter model: A model object assined to the SelectableModel protocol + /// - Returns: Boolean determining if the passed model should be deselected. + func toDeselect(model: SelectableMoleculeModel) -> Bool { + !selectAllState && model.selectedValue } } From be196a289e9a5d4102d18918fd963e321c3aa80c Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 22 Jun 2021 13:10:06 -0400 Subject: [PATCH 14/44] aligns behavior for user intiaited corner cases. --- .../Atoms/Selectors/CheckboxModel.swift | 4 +- .../Behaviors/SelectAllBoxesBehavior.swift | 108 +++++++++++++++--- 2 files changed, 94 insertions(+), 18 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift index 0b98d1fc..34f0fd22 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift @@ -7,7 +7,7 @@ // -@objcMembers public class CheckboxModel: MoleculeModelProtocol, SelectableMoleculeModel, FormFieldProtocol { +@objcMembers public class CheckboxModel: NSObject, MoleculeModelProtocol, SelectableMoleculeModel, FormFieldProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -15,7 +15,7 @@ public static var identifier: String = "checkbox" public var backgroundColor: Color? public var accessibilityIdentifier: String? - public var checked: Bool = false + public dynamic var checked: Bool = false public var enabled: Bool = true public var animated: Bool = true public var inverted: Bool = false diff --git a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift index 93d7367e..27cbe69a 100644 --- a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift +++ b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift @@ -24,7 +24,7 @@ public class SelectAllBoxesBehaviorModel: PageBehaviorModelProtocol { //-------------------------------------------------- // MARK: - Codable //-------------------------------------------------- - + private enum CodingKeys: String, CodingKey { case selectAllTitle case deselectAllTitle @@ -41,7 +41,7 @@ public class SelectAllBoxesBehaviorModel: PageBehaviorModelProtocol { self.deselectAllTitle = deselectAllTitle } } - + public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(selectAllTitle, forKey: .selectAllTitle) @@ -50,16 +50,23 @@ public class SelectAllBoxesBehaviorModel: PageBehaviorModelProtocol { } /// Selects all the control models presented on a page. -public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior { +public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior, PageMoleculeTransformationBehavior { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- /// Status of the select all behavior. Initially false as the action has not been enaged. - var selectAllState = false + var didSelectAllState = false + /// Reference to the general PageBehaviorModel. var model: PageBehaviorModelProtocol + /// Dictionary of KVOs to observing the selected property of each `SelectableMoleculeModel`. + private var observers = [String: NSKeyValueObservation?]() + + /// A store representing the values of the `SelectableMoleculeModel`. + private var valuesMirror = [String: Bool]() + //-------------------------------------------------- // MARK: - Delegate //-------------------------------------------------- @@ -75,6 +82,45 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior { self.delegate = delegateObject } + public func onPageNew(rootMolecules: [MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject) { + + let selectableModels: [SelectableMoleculeModel] = rootMolecules.allMoleculesOfType() + + guard !selectableModels.isEmpty else { return } + + for model in selectableModels { + if let checkboxModel = model as? CheckboxModel, let key = checkboxModel.fieldKey { + + valuesMirror[key] = checkboxModel.checked + + observers[key] = checkboxModel.observe(\.checked, options: [.new]) { [weak self] model, change in + guard let self = self, + let isChecked = change.newValue, + let key = model.fieldKey + else { return } + + self.valuesMirror[key] = isChecked + + // If all are models are in the opposite state of the behavior, then realign. + if self.selectAllIsMisaligned() { + self.realignPageBehavior(asSelectAll: true) + + } else if self.deselectAllIsMisaligned() { + self.realignPageBehavior(asSelectAll: false) + } + } + } + } + } + + //-------------------------------------------------- + // MARK: - Deinit + //-------------------------------------------------- + + deinit { + observers.values.forEach { $0?.invalidate() } + } + //-------------------------------------------------- // MARK: - Custom Action //-------------------------------------------------- @@ -91,25 +137,45 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior { // Verify we have the correct action type and necessary values. guard actionType == "selectAllBoxes", let selectableModels: [SelectableMoleculeModel] = delegate?.moleculeDelegate?.getRootMolecules().allMoleculesOfType(), - !selectableModels.isEmpty, - let model = model as? SelectAllBoxesBehaviorModel + !selectableModels.isEmpty else { return false } // Flip the selected state of the behavior. - selectAllState.toggle() + didSelectAllState.toggle() // Iterate through selectable molecules. for selectableModel in selectableModels { if toSelect(model: selectableModel) || toDeselect(model: selectableModel) { - selectableModel.select(as: selectAllState) + selectableModel.select(as: didSelectAllState) } } - // Get title to update the nav button title. - let navButtonTitle: String? = selectAllState ? model.deselectAllTitle : model.selectAllTitle + updatePageNavigationUI() + return true + } + + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + + /// In the event that the user manually selects or deselects all `SelectableMoleculeModel` + /// the behavior will need to reflect the inverse of its previously expected action. + /// Initiates the navigation and page behavior realignment + /// - Parameter asSelectAll: The actual value didSelectAllState ought to be. + func realignPageBehavior(asSelectAll: Bool) { + didSelectAllState = asSelectAll + updatePageNavigationUI() + } + + /// Updates the navigation UI to correctly reflect the behavior's state. + func updatePageNavigationUI() { - MVMCoreDispatchUtility.performBlock(onMainThread: { - guard let controller = self.delegate?.moleculeDelegate as? ViewController else { return } + guard let model = model as? SelectAllBoxesBehaviorModel else { return } + + let navButtonTitle: String? = didSelectAllState ? model.deselectAllTitle : model.selectAllTitle + + MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in + guard let controller = self?.delegate?.moleculeDelegate as? ViewController else { return } controller.handleNewDataAndUpdateUI() if MVMCoreUIUtility.getCurrentVisibleController() == controller { @@ -117,21 +183,31 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior { controller.manager?.refreshNavigationUI() } }) - - return true + } + + /// Convenience function for readability to confirmt he state of the behavior. + /// - Returns: Boolean indicating that the behavior's `didSelectAllState` is false while all model values are true (selected). + func selectAllIsMisaligned() -> Bool { + !didSelectAllState && valuesMirror.values.allSatisfy { $0 == true } + } + + /// Convenience function for readability to confirmt he state of the behavior. + /// - Returns: Boolean indicating that the behavior's `didSelectAllState` is true while all model values are false (deselected). + func deselectAllIsMisaligned() -> Bool { + didSelectAllState && valuesMirror.values.allSatisfy { $0 == false } } /// Convenience function making it easier to read if a current selectable model should be acted on. /// - Parameter model: A model object assined to the SelectableModel protocol /// - Returns: Boolean determining if the passed model should be selected. func toSelect(model: SelectableMoleculeModel) -> Bool { - selectAllState && !model.selectedValue + didSelectAllState && !model.selectedValue } /// Convenience function making it easier to read if a current selectable model should be acted on. /// - Parameter model: A model object assined to the SelectableModel protocol /// - Returns: Boolean determining if the passed model should be deselected. func toDeselect(model: SelectableMoleculeModel) -> Bool { - !selectAllState && model.selectedValue + !didSelectAllState && model.selectedValue } } From 2b378f55973d1894c3210f84ba7a61df79e3574c Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 22 Jun 2021 15:05:04 -0400 Subject: [PATCH 15/44] generalizing the observing behavior --- .../Atomic/Atoms/Selectors/Checkbox.swift | 6 +-- .../Atoms/Selectors/CheckboxModel.swift | 20 +++---- MVMCoreUI/Atomic/Atoms/Selectors/Toggle.swift | 4 +- .../Atomic/Atoms/Selectors/ToggleModel.swift | 20 +++---- .../Behaviors/SelectAllBoxesBehavior.swift | 52 ++++++++++--------- 5 files changed, 48 insertions(+), 54 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/Checkbox.swift b/MVMCoreUI/Atomic/Atoms/Selectors/Checkbox.swift index f1fd5fed..a5657dd4 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/Checkbox.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/Checkbox.swift @@ -124,7 +124,7 @@ import MVMCore didSet { if !updateSelectionOnly { layoutIfNeeded() - (model as? CheckboxModel)?.checked = isSelected + (model as? CheckboxModel)?.selected = isSelected shapeLayer?.removeAllAnimations() updateCheckboxUI(isSelected: isSelected, isAnimated: isAnimated) _ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate) @@ -419,8 +419,8 @@ import MVMCore isAnimated = model.animated isRound = model.round - if model.checked { - checkAndBypassAnimations(selected: model.checked) + if model.selected { + checkAndBypassAnimations(selected: model.selected) } isEnabled = model.enabled diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift index 34f0fd22..b7d79570 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift @@ -15,7 +15,7 @@ public static var identifier: String = "checkbox" public var backgroundColor: Color? public var accessibilityIdentifier: String? - public dynamic var checked: Bool = false + public dynamic var selected: Bool = false public var enabled: Bool = true public var animated: Bool = true public var inverted: Bool = false @@ -69,26 +69,22 @@ // MARK: - Form Validation //-------------------------------------------------- - public func formFieldValue() -> AnyHashable? { checked } + public func formFieldValue() -> AnyHashable? { selected } //-------------------------------------------------- // MARK: - Selectable Protocol //-------------------------------------------------- public func select(as isSelected: Bool) { - checked = isSelected + selected = isSelected } - - public var selectedValue: Bool { - checked - } - + //-------------------------------------------------- // MARK: - Initializer //-------------------------------------------------- public init(isChecked: Bool = false) { - self.checked = isChecked + self.selected = isChecked baseValue = isChecked } @@ -142,10 +138,10 @@ } if let checked = try typeContainer.decodeIfPresent(Bool.self, forKey: .checked) { - self.checked = checked + self.selected = checked } - baseValue = checked + baseValue = selected if let animated = try typeContainer.decodeIfPresent(Bool.self, forKey: .animated) { self.animated = animated @@ -179,7 +175,7 @@ try container.encodeIfPresent(fieldKey, forKey: .fieldKey) try container.encodeIfPresent(borderColor, forKey: .borderColor) try container.encode(borderWidth, forKey: .borderWidth) - try container.encode(checked, forKey: .checked) + try container.encode(selected, forKey: .checked) try container.encode(inverted, forKey: .inverted) try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier) try container.encodeIfPresent(checkColor, forKey: .checkColor) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/Toggle.swift b/MVMCoreUI/Atomic/Atoms/Selectors/Toggle.swift index 304b23c4..3513a03b 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/Toggle.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/Toggle.swift @@ -98,7 +98,7 @@ public typealias ActionBlockConfirmation = () -> (Bool) self.constrainKnob() } - toggleModel?.state = isOn + toggleModel?.selected = isOn _ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate) accessibilityValue = isOn ? MVMCoreUIUtility.hardcodedString(withKey: "AccOn") : MVMCoreUIUtility.hardcodedString(withKey: "AccOff") setNeedsLayout() @@ -381,7 +381,7 @@ public typealias ActionBlockConfirmation = () -> (Bool) containerTintColor.off = model.offTintColor.uiColor knobTintColor.on = model.onKnobTintColor.uiColor knobTintColor.off = model.offKnobTintColor.uiColor - isOn = model.state + isOn = model.selected changeStateNoAnimation(isOn) isAnimated = model.animated isEnabled = model.enabled diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift index e59a4738..565d8d43 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift @@ -7,7 +7,7 @@ // -public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableModelProtocol, SelectableMoleculeModel { +public class ToggleModel: NSObject, MoleculeModelProtocol, FormFieldProtocol, EnableableModelProtocol, SelectableMoleculeModel { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -15,7 +15,7 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo public static var identifier: String = "toggle" public var accessibilityIdentifier: String? public var backgroundColor: Color? - public var state: Bool = false + public dynamic var selected: Bool = false public var animated: Bool = true public var enabled: Bool = true public var action: ActionModelProtocol? @@ -56,18 +56,14 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo // MARK: - Form Valdiation //-------------------------------------------------- - public func formFieldValue() -> AnyHashable? { state } + public func formFieldValue() -> AnyHashable? { selected } //-------------------------------------------------- // MARK: - Selectable Protocol //-------------------------------------------------- public func select(as isSelected: Bool) { - state = isSelected - } - - public var selectedValue: Bool { - state + selected = isSelected } //-------------------------------------------------- @@ -75,7 +71,7 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo //-------------------------------------------------- public init(_ state: Bool) { - self.state = state + self.selected = state baseValue = state } @@ -87,7 +83,7 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo let typeContainer = try decoder.container(keyedBy: CodingKeys.self) if let state = try typeContainer.decodeIfPresent(Bool.self, forKey: .state) { - self.state = state + self.selected = state } if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) { @@ -121,7 +117,7 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText) - baseValue = state + baseValue = selected fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey) if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) { self.groupName = groupName @@ -135,7 +131,7 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo try container.encodeModelIfPresent(action, forKey: .action) try container.encodeModelIfPresent(alternateAction, forKey: .alternateAction) try container.encode(moleculeName, forKey: .moleculeName) - try container.encode(state, forKey: .state) + try container.encode(selected, forKey: .state) try container.encode(animated, forKey: .animated) try container.encode(enabled, forKey: .enabled) try container.encode(onTintColor, forKey: .onTintColor) diff --git a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift index 27cbe69a..b4db84d5 100644 --- a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift +++ b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift @@ -9,8 +9,8 @@ /// Protocol to apply to any model of a UI Control with a binary on/off nature. /// /// Example classes: Checkbox or Switch. -public protocol SelectableMoleculeModel { - var selectedValue: Bool { get } +@objc public protocol SelectableMoleculeModel: AnyObject { + @objc dynamic var selected: Bool { get set } func select(as isSelected: Bool) } @@ -84,31 +84,33 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior, PageMolecu public func onPageNew(rootMolecules: [MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject) { - let selectableModels: [SelectableMoleculeModel] = rootMolecules.allMoleculesOfType() + let selectableModels: [(NSObject & SelectableMoleculeModel)] = rootMolecules.allMoleculesOfType() guard !selectableModels.isEmpty else { return } - + for model in selectableModels { - if let checkboxModel = model as? CheckboxModel, let key = checkboxModel.fieldKey { + if let key = (model as? FormFieldProtocol)?.fieldKey { + valuesMirror[key] = model.selected + setObserver(model, fieldKey: key) + } + } + } + + func setObserver(_ model: T, fieldKey: String) where T: (NSObject & SelectableMoleculeModel) { + + observers[fieldKey] = model.observe(\.selected, options: [.new]) { [weak self] model, change in + guard let self = self, + let isChecked = change.newValue + else { return } + + self.valuesMirror[fieldKey] = isChecked + + // If all are models are in the opposite state of the behavior, then realign. + if self.selectAllIsMisaligned() { + self.realignPageBehavior(asSelectAll: true) - valuesMirror[key] = checkboxModel.checked - - observers[key] = checkboxModel.observe(\.checked, options: [.new]) { [weak self] model, change in - guard let self = self, - let isChecked = change.newValue, - let key = model.fieldKey - else { return } - - self.valuesMirror[key] = isChecked - - // If all are models are in the opposite state of the behavior, then realign. - if self.selectAllIsMisaligned() { - self.realignPageBehavior(asSelectAll: true) - - } else if self.deselectAllIsMisaligned() { - self.realignPageBehavior(asSelectAll: false) - } - } + } else if self.deselectAllIsMisaligned() { + self.realignPageBehavior(asSelectAll: false) } } } @@ -201,13 +203,13 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior, PageMolecu /// - Parameter model: A model object assined to the SelectableModel protocol /// - Returns: Boolean determining if the passed model should be selected. func toSelect(model: SelectableMoleculeModel) -> Bool { - didSelectAllState && !model.selectedValue + didSelectAllState && !model.selected } /// Convenience function making it easier to read if a current selectable model should be acted on. /// - Parameter model: A model object assined to the SelectableModel protocol /// - Returns: Boolean determining if the passed model should be deselected. func toDeselect(model: SelectableMoleculeModel) -> Bool { - !didSelectAllState && model.selectedValue + !didSelectAllState && model.selected } } From f27e3cd680a1ec473054a5e6ef9cb495ffd67388 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 22 Jun 2021 15:22:27 -0400 Subject: [PATCH 16/44] updated protocol --- MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift | 8 -------- MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift | 8 -------- MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift | 5 ++--- 3 files changed, 2 insertions(+), 19 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift index b7d79570..4efa53ec 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift @@ -71,14 +71,6 @@ public func formFieldValue() -> AnyHashable? { selected } - //-------------------------------------------------- - // MARK: - Selectable Protocol - //-------------------------------------------------- - - public func select(as isSelected: Bool) { - selected = isSelected - } - //-------------------------------------------------- // MARK: - Initializer //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift index 565d8d43..88f193f5 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift @@ -58,14 +58,6 @@ public class ToggleModel: NSObject, MoleculeModelProtocol, FormFieldProtocol, En public func formFieldValue() -> AnyHashable? { selected } - //-------------------------------------------------- - // MARK: - Selectable Protocol - //-------------------------------------------------- - - public func select(as isSelected: Bool) { - selected = isSelected - } - //-------------------------------------------------- // MARK: - Initializer //-------------------------------------------------- diff --git a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift index b4db84d5..e9ffce2c 100644 --- a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift +++ b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift @@ -8,10 +8,9 @@ /// Protocol to apply to any model of a UI Control with a binary on/off nature. /// -/// Example classes: Checkbox or Switch. +/// Example classes: Checkbox or Toggle. @objc public protocol SelectableMoleculeModel: AnyObject { @objc dynamic var selected: Bool { get set } - func select(as isSelected: Bool) } public class SelectAllBoxesBehaviorModel: PageBehaviorModelProtocol { @@ -148,7 +147,7 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior, PageMolecu // Iterate through selectable molecules. for selectableModel in selectableModels { if toSelect(model: selectableModel) || toDeselect(model: selectableModel) { - selectableModel.select(as: didSelectAllState) + selectableModel.selected = didSelectAllState } } From 5947e5c1ade83b90cbdfe80ea5296f71ff2d1a85 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 24 Jun 2021 12:12:54 -0400 Subject: [PATCH 17/44] updated name --- MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift index e9ffce2c..d16c6cd6 100644 --- a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift +++ b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift @@ -9,7 +9,7 @@ /// Protocol to apply to any model of a UI Control with a binary on/off nature. /// /// Example classes: Checkbox or Toggle. -@objc public protocol SelectableMoleculeModel: AnyObject { +@objc public protocol SelectableMoleculeModelProtocol: AnyObject { @objc dynamic var selected: Bool { get set } } From 90e6dfd08429b38e63e90110acb827230c1ab017 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 24 Jun 2021 13:59:37 -0400 Subject: [PATCH 18/44] nav dev --- MVMCoreUI.xcodeproj/project.pbxproj | 4 + .../Atoms/Selectors/CheckboxModel.swift | 2 +- .../Atomic/Atoms/Selectors/ToggleModel.swift | 2 +- .../SelectAllNavigationLabelButton.swift | 82 +++++++++++++++++++ .../Behaviors/SelectAllBoxesBehavior.swift | 61 ++++---------- .../OtherHandlers/CoreUIModelMapping.swift | 1 + 6 files changed, 105 insertions(+), 47 deletions(-) create mode 100644 MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/SelectAllNavigationLabelButton.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index b90b6f5e..281a6ffc 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -74,6 +74,7 @@ 0A25209824645B76000FA9F6 /* TextViewEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A25209724645B76000FA9F6 /* TextViewEntryFieldModel.swift */; }; 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */; }; 0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */; }; + 0A423A202684E7A0008EC258 /* SelectAllNavigationLabelButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A423A1F2684E7A0008EC258 /* SelectAllNavigationLabelButton.swift */; }; 0A51F3E22475CB73002E08B6 /* LoadingSpinnerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A51F3E02475CB73002E08B6 /* LoadingSpinnerModel.swift */; }; 0A51F3E32475CB73002E08B6 /* LoadingSpinner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A51F3E12475CB73002E08B6 /* LoadingSpinner.swift */; }; 0A5D59C223AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */; }; @@ -636,6 +637,7 @@ 0A25209724645B76000FA9F6 /* TextViewEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewEntryFieldModel.swift; sourceTree = ""; }; 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CATransaction+Extension.swift"; sourceTree = ""; }; 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEntryField.swift; sourceTree = ""; }; + 0A423A1F2684E7A0008EC258 /* SelectAllNavigationLabelButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectAllNavigationLabelButton.swift; sourceTree = ""; }; 0A51F3E02475CB73002E08B6 /* LoadingSpinnerModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadingSpinnerModel.swift; sourceTree = ""; }; 0A51F3E12475CB73002E08B6 /* LoadingSpinner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadingSpinner.swift; sourceTree = ""; }; 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleGuidelinesProtocol.swift; sourceTree = ""; }; @@ -1755,6 +1757,7 @@ D23EA801247EBED400D60C34 /* ImageBarButtonItem.swift */, D23EA7FD247EBBB700D60C34 /* NavigationLabelButtonModel.swift */, D23EA7FF247EBD6C00D60C34 /* LabelBarButtonItem.swift */, + 0A423A1F2684E7A0008EC258 /* SelectAllNavigationLabelButton.swift */, ); path = Buttons; sourceTree = ""; @@ -2730,6 +2733,7 @@ D264FA8E243BCD9A00D98315 /* CollectionTemplate.swift in Sources */, 0A7EF85B23D8A52800B2AAD1 /* EntryFieldModel.swift in Sources */, AA633B3124989EC000731E80 /* HeadersH2PricingTwoRowsModel.swift in Sources */, + 0A423A202684E7A0008EC258 /* SelectAllNavigationLabelButton.swift in Sources */, 8DEFA95C243DAC20000D27E5 /* ListThreeColumnDataUsageDividerModel.swift in Sources */, D2092357244FA1EF0044AD09 /* ThreeLayerModelBase.swift in Sources */, D2FD4A4925199BD9000C28A9 /* AccessibilityProtocol.swift in Sources */, diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift index 4efa53ec..87c4568d 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift @@ -7,7 +7,7 @@ // -@objcMembers public class CheckboxModel: NSObject, MoleculeModelProtocol, SelectableMoleculeModel, FormFieldProtocol { +@objcMembers public class CheckboxModel: NSObject, MoleculeModelProtocol, SelectableMoleculeModelProtocol, FormFieldProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift index 88f193f5..0fb42632 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift @@ -7,7 +7,7 @@ // -public class ToggleModel: NSObject, MoleculeModelProtocol, FormFieldProtocol, EnableableModelProtocol, SelectableMoleculeModel { +public class ToggleModel: NSObject, MoleculeModelProtocol, FormFieldProtocol, EnableableModelProtocol, SelectableMoleculeModelProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/SelectAllNavigationLabelButton.swift b/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/SelectAllNavigationLabelButton.swift new file mode 100644 index 00000000..f166e9fb --- /dev/null +++ b/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/SelectAllNavigationLabelButton.swift @@ -0,0 +1,82 @@ +// +// SelectAllNavigationLabelButton.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 6/24/21. +// Copyright © 2021 Verizon Wireless. All rights reserved. +// + + +public class SelectAllNavigationLabelButton: NavigationButtonModelProtocol, MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public var backgroundColor: Color? + public static var identifier: String = "selectAllNavigationLabelButton" + public var accessibilityIdentifier: String? + public var willSelect: Bool + public var selectAllTitle: String = "Select All" + public var deselectAllTitle: String = "Deselect All" + public var action: ActionModelProtocol + + public var selectionTitle: String { + willSelect ? selectAllTitle : deselectAllTitle + } + + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + + public init(willSelect: Bool, selectAllTitle: String, deselectAllTitle: String, action: ActionModelProtocol) { + self.willSelect = willSelect + self.action = action + self.selectAllTitle = selectAllTitle + self.deselectAllTitle = deselectAllTitle + } + + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + + private enum CodingKeys: String, CodingKey { + case moleculeName + case accessibilityIdentifier + case willSelect + case selectAllTitle + case deselectAllTitle + case action + } + + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier) + selectAllTitle = try typeContainer.decode(String.self, forKey: .selectAllTitle) + deselectAllTitle = try typeContainer.decode(String.self, forKey: .deselectAllTitle) + willSelect = try typeContainer.decode(Bool.self, forKey: .willSelect) + action = try typeContainer.decodeModel(codingKey: .action) + } + + open func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier) + try container.encode(selectAllTitle, forKey: .selectAllTitle) + try container.encode(deselectAllTitle, forKey: .deselectAllTitle) + try container.encode(willSelect, forKey: .willSelect) + try container.encodeModel(action, forKey: .action) + } + + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + + /// Convenience function that creates a BarButtonItem for the model. + public func createNavigationItemButton(delegateObject: MVMCoreUIDelegateObject? = nil, additionalData: [AnyHashable: Any]? = nil) -> UIBarButtonItem { + LabelBarButtonItem.create(with: selectionTitle, actionModel: action, delegateObject: delegateObject, additionalData: additionalData) + } +} diff --git a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift index d16c6cd6..9b50a4a2 100644 --- a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift +++ b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift @@ -16,36 +16,7 @@ public class SelectAllBoxesBehaviorModel: PageBehaviorModelProtocol { public class var identifier: String { "pageSelectAllBoxesBehavior" } public var shouldAllowMultipleInstances: Bool { false } - public var selectAllTitle: String = "Select All" - public var deselectAllTitle: String = "Deselect All" public init() { } - - //-------------------------------------------------- - // MARK: - Codable - //-------------------------------------------------- - - private enum CodingKeys: String, CodingKey { - case selectAllTitle - case deselectAllTitle - } - - required public init(from decoder: Decoder) throws { - let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - - if let selectAllTitle = try typeContainer.decodeIfPresent(String.self, forKey: .selectAllTitle) { - self.selectAllTitle = selectAllTitle - } - - if let deselectAllTitle = try typeContainer.decodeIfPresent(String.self, forKey: .deselectAllTitle) { - self.deselectAllTitle = deselectAllTitle - } - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(selectAllTitle, forKey: .selectAllTitle) - try container.encode(deselectAllTitle, forKey: .deselectAllTitle) - } } /// Selects all the control models presented on a page. @@ -83,7 +54,7 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior, PageMolecu public func onPageNew(rootMolecules: [MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject) { - let selectableModels: [(NSObject & SelectableMoleculeModel)] = rootMolecules.allMoleculesOfType() + let selectableModels: [(NSObject & SelectableMoleculeModelProtocol)] = rootMolecules.allMoleculesOfType() guard !selectableModels.isEmpty else { return } @@ -95,7 +66,7 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior, PageMolecu } } - func setObserver(_ model: T, fieldKey: String) where T: (NSObject & SelectableMoleculeModel) { + func setObserver(_ model: T, fieldKey: String) where T: (NSObject & SelectableMoleculeModelProtocol) { observers[fieldKey] = model.observe(\.selected, options: [.new]) { [weak self] model, change in guard let self = self, @@ -137,7 +108,7 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior, PageMolecu // Verify we have the correct action type and necessary values. guard actionType == "selectAllBoxes", - let selectableModels: [SelectableMoleculeModel] = delegate?.moleculeDelegate?.getRootMolecules().allMoleculesOfType(), + let selectableModels: [SelectableMoleculeModelProtocol] = delegate?.moleculeDelegate?.getRootMolecules().allMoleculesOfType(), !selectableModels.isEmpty else { return false } @@ -170,20 +141,20 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior, PageMolecu /// Updates the navigation UI to correctly reflect the behavior's state. func updatePageNavigationUI() { - guard let model = model as? SelectAllBoxesBehaviorModel else { return } - let navButtonTitle: String? = didSelectAllState ? model.deselectAllTitle : model.selectAllTitle +// let navButtonTitle: String? = didSelectAllState ? model.deselectAllTitle : model.selectAllTitle + // TODO: update - MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in - guard let controller = self?.delegate?.moleculeDelegate as? ViewController else { return } - controller.handleNewDataAndUpdateUI() - - if MVMCoreUIUtility.getCurrentVisibleController() == controller { - controller.navigationItem.rightBarButtonItem?.title = navButtonTitle - controller.manager?.refreshNavigationUI() - } - }) +// MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in +// guard let controller = self?.delegate?.moleculeDelegate as? PageProtocol else { return } +// controller.handleNewDataAndUpdateUI() +// let n = controller.getNavigationModel() +// let r = n?.additionalRightButtons +// for i in r! { +// i.moleculeName +// } +// }) } /// Convenience function for readability to confirmt he state of the behavior. @@ -201,14 +172,14 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior, PageMolecu /// Convenience function making it easier to read if a current selectable model should be acted on. /// - Parameter model: A model object assined to the SelectableModel protocol /// - Returns: Boolean determining if the passed model should be selected. - func toSelect(model: SelectableMoleculeModel) -> Bool { + func toSelect(model: SelectableMoleculeModelProtocol) -> Bool { didSelectAllState && !model.selected } /// Convenience function making it easier to read if a current selectable model should be acted on. /// - Parameter model: A model object assined to the SelectableModel protocol /// - Returns: Boolean determining if the passed model should be deselected. - func toDeselect(model: SelectableMoleculeModel) -> Bool { + func toDeselect(model: SelectableMoleculeModelProtocol) -> Bool { !didSelectAllState && model.selected } } diff --git a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift index 437b2e01..f33943e1 100644 --- a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift +++ b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift @@ -129,6 +129,7 @@ open class CoreUIModelMapping: ModelMapping { try? ModelRegistry.register(NavigationItemModel.self) try? ModelRegistry.register(NavigationImageButtonModel.self) try? ModelRegistry.register(NavigationLabelButtonModel.self) + try? ModelRegistry.register(SelectAllNavigationLabelButton.self) // MARK:- Other Organisms try? ModelRegistry.register(handler: Carousel.self, for: CarouselModel.self) From 1109931d8e6f294a8c5340ba90351ae16194034d Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 24 Jun 2021 14:30:49 -0400 Subject: [PATCH 19/44] removed commented code. --- MVMCoreUI/Behaviors/PlayAudioBehavior.swift | 156 -------------------- 1 file changed, 156 deletions(-) diff --git a/MVMCoreUI/Behaviors/PlayAudioBehavior.swift b/MVMCoreUI/Behaviors/PlayAudioBehavior.swift index 7ea37809..b555eb01 100644 --- a/MVMCoreUI/Behaviors/PlayAudioBehavior.swift +++ b/MVMCoreUI/Behaviors/PlayAudioBehavior.swift @@ -71,160 +71,4 @@ public class PagePlayAudioBehavior: PageCustomActionHandlerBehavior { public func onPageHidden(_ delegateObject: MVMCoreUIDelegateObject?) { // TODO: Stop player } - - -// func saveVoicemailToDocumentDirectory(voicemail:String) -> URL { -// let voicemailUrl = URL(string: "fileNotFound")! -// ///Setting Voicemail Path -// -// let cacheDirectory = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first as NSString? -// -// if let cachePath = cacheDirectory?.appendingPathComponent("fdv.voicemails"), !FileManager.default.fileExists(atPath: cachePath) { -// do{ -// try FileManager.default.createDirectory(atPath: cachePath, withIntermediateDirectories: false, attributes: nil) -// } catch let error as NSError { -// MVMCoreLoggingHandler.logDebugMessage(withDelegate: error.debugDescription) -// } -// } -// let fileName = cacheDirectory?.appendingPathComponent("fdv.voicemails").appending("/VM_1.wmv") -//#warning("Pending task to check if we can protect the voicemail data") -// -// let voicemailData = Data(base64Encoded: voicemail) -// do{ -// if let _fileName = fileName, let fileUrl = URL(string: _fileName) { -// try voicemailData?.write(to: fileUrl, options: .completeFileProtection) -// return fileUrl -// } -// } catch let error as NSError { -// MVMCoreLoggingHandler.logDebugMessage(withDelegate: error.debugDescription) -// } -// return voicemailUrl -// } - - -// NSDictionary *completeProtection = [NSDictionary dictionaryWithObject:NSFileProtectionComplete forKey:NSFileProtectionKey]; -// [[NSFileManager defaultManager] setAttributes:completeProtection ofItemAtPath:appFile error:nil]; -// return ([data writeToFile:appFile atomically:YES]); - - -// func downloadVoicemail(url: URL?) { -// -// let downloadTask = URLSession.shared.downloadTask(with: url!) { url, response, error in -// guard error == nil, let fileURL = url else { return } -// do { -// let documentsURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) -// let savedURL = documentsURL.appendingPathComponent(fileURL.lastPathComponent) -// try FileManager.default.moveItem(at: fileURL, to: savedURL) -// -// } catch let error as NSError { -// MVMCoreLoggingHandler.logDebugMessage(withDelegate: error.debugDescription) -// } -// } -// downloadTask.resume() -// } - -/* - // https://oneconfluence.verizon.com/pages/viewpage.action?spaceKey=EIM&title=FDV+API - - /// The directory to store all downloaded voicemails. - func voicemailDirectory() -> URL? { - - guard let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return nil } - return documentsURL.appendingPathComponent("fios_vm") - } - - func voicemailListQuery(accountId: String, sourceIP: String, mdn: String, mailBoxNo: String, timeZone: String) { - - let url = URL(string: "")! - var request = URLRequest(url: url) - request.httpMethod = "POST" - - let task = URLSession.shared.dataTask(with: request) { data, response, error in - // do something with the result - // print(data) -// if let data = data { - // TODO: Receive List of MDNs - // if let data = data, let dataString = String(data: data, encoding: .utf8) { - // print("Response data string:\n \(dataString)") - // } - // print(String(data: data, encoding: .utf8)) -// } else { - // print("no data") -// } - } - - task.resume() - - } - - func fetchVoicemail(accountId: String, sourceIP: String, mdn: String, mailBoxNo: String) { - -// guard let messageID = messageID else { return } - - let url = URL(string: "")! - var request = URLRequest(url: url) - request.httpMethod = "POST" - - let task = URLSession.shared.dataTask(with: request) { data, response, error in - // do something with the result - // print(data) -// if let data = data { - //body/VoiceMailMessages/Stream/TN/VMID/Audio/bin - // TODO: Receive List of MDNs - // if let data = data, let dataString = String(data: data, encoding: .utf8) { - // print("Response data string:\n \(dataString)") - // } - // print(String(data: data, encoding: .utf8)) -// } else { - // print("no data") -// } - } - - task.resume() - - // TODO: Fetch Audio file. - } - - func downloadVoicemail(url: URL?) { - - let downloadTask = URLSession.shared.downloadTask(with: url!) { [weak self] url, response, error in - guard error == nil, - let fileURL = url - else { return } - - do { - // "data/user/0/com.verizon.myfios/files/VM_INBOX-8711.wav" - let documentsURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) - let savedURL = documentsURL.appendingPathComponent(fileURL.lastPathComponent) - try FileManager.default.moveItem(at: fileURL, to: savedURL) - self?.audioFilePath = savedURL - } catch let error as NSError { - MVMCoreLoggingHandler.logDebugMessage(withDelegate: error.debugDescription) - } - } - downloadTask.resume() - } - - func fetchAudioFilePath() { - - guard let messageID = messageID, // "INBOX-8711" - let cleanMDN = cleanMDN, // "4124712342" - let destinationURL = voicemailDirectory() - else { return } - - let uri = "com.verizon.fios.voice2/downloadvm?VM_DOWNLOAD_URI_DATA_MESSAGE_ID=\(messageID)&VM_DOWNLOAD_URI_DATA_TN=\(cleanMDN)" - let url = URL(string: uri) - - - // TODO: First check to see if the file is stored on disk, if not, then downloaded. - createDirectoryIfNeeded(url: destinationURL) - - if FileManager.default.fileExists(atPath: destinationURL.path) { - audioFilePath = destinationURL - - } else { - downloadVoicemail(url: url) - } - } - */ } From e79c1591387c1ade95bcf2586713d67ceec96988 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 24 Jun 2021 16:30:52 -0400 Subject: [PATCH 20/44] select all behavior. --- .../SelectAllNavigationLabelButton.swift | 8 +-- .../Behaviors/SelectAllBoxesBehavior.swift | 68 +++++++++++-------- 2 files changed, 42 insertions(+), 34 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/SelectAllNavigationLabelButton.swift b/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/SelectAllNavigationLabelButton.swift index f166e9fb..59bf6136 100644 --- a/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/SelectAllNavigationLabelButton.swift +++ b/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/SelectAllNavigationLabelButton.swift @@ -15,7 +15,7 @@ public class SelectAllNavigationLabelButton: NavigationButtonModelProtocol, Mole public var backgroundColor: Color? public static var identifier: String = "selectAllNavigationLabelButton" public var accessibilityIdentifier: String? - public var willSelect: Bool + public var willSelect: Bool = true public var selectAllTitle: String = "Select All" public var deselectAllTitle: String = "Deselect All" public var action: ActionModelProtocol @@ -44,7 +44,7 @@ public class SelectAllNavigationLabelButton: NavigationButtonModelProtocol, Mole case accessibilityIdentifier case willSelect case selectAllTitle - case deselectAllTitle + case deSelectAllTitle case action } @@ -56,7 +56,7 @@ public class SelectAllNavigationLabelButton: NavigationButtonModelProtocol, Mole let typeContainer = try decoder.container(keyedBy: CodingKeys.self) accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier) selectAllTitle = try typeContainer.decode(String.self, forKey: .selectAllTitle) - deselectAllTitle = try typeContainer.decode(String.self, forKey: .deselectAllTitle) + deselectAllTitle = try typeContainer.decode(String.self, forKey: .deSelectAllTitle) willSelect = try typeContainer.decode(Bool.self, forKey: .willSelect) action = try typeContainer.decodeModel(codingKey: .action) } @@ -66,7 +66,7 @@ public class SelectAllNavigationLabelButton: NavigationButtonModelProtocol, Mole try container.encode(moleculeName, forKey: .moleculeName) try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier) try container.encode(selectAllTitle, forKey: .selectAllTitle) - try container.encode(deselectAllTitle, forKey: .deselectAllTitle) + try container.encode(deselectAllTitle, forKey: .deSelectAllTitle) try container.encode(willSelect, forKey: .willSelect) try container.encodeModel(action, forKey: .action) } diff --git a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift index 9b50a4a2..1f7326fd 100644 --- a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift +++ b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift @@ -26,7 +26,10 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior, PageMolecu //-------------------------------------------------- /// Status of the select all behavior. Initially false as the action has not been enaged. - var didSelectAllState = false + var willSelectAllState: Bool { + get { getSelectAllNavbutton()?.willSelect ?? false } + set { getSelectAllNavbutton()?.willSelect = newValue } + } /// Reference to the general PageBehaviorModel. var model: PageBehaviorModelProtocol @@ -57,7 +60,7 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior, PageMolecu let selectableModels: [(NSObject & SelectableMoleculeModelProtocol)] = rootMolecules.allMoleculesOfType() guard !selectableModels.isEmpty else { return } - + for model in selectableModels { if let key = (model as? FormFieldProtocol)?.fieldKey { valuesMirror[key] = model.selected @@ -77,10 +80,10 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior, PageMolecu // If all are models are in the opposite state of the behavior, then realign. if self.selectAllIsMisaligned() { - self.realignPageBehavior(asSelectAll: true) + self.realignPageBehaviorAs(willSelectAll: false) } else if self.deselectAllIsMisaligned() { - self.realignPageBehavior(asSelectAll: false) + self.realignPageBehaviorAs(willSelectAll: true) } } } @@ -112,13 +115,13 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior, PageMolecu !selectableModels.isEmpty else { return false } - // Flip the selected state of the behavior. - didSelectAllState.toggle() + // Hold value dues to asynch behavior of page refreshing. + let newSelectedState = willSelectAllState // Iterate through selectable molecules. for selectableModel in selectableModels { if toSelect(model: selectableModel) || toDeselect(model: selectableModel) { - selectableModel.selected = didSelectAllState + selectableModel.selected = newSelectedState } } @@ -130,56 +133,61 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior, PageMolecu // MARK: - Methods //-------------------------------------------------- + func getSelectAllNavbutton() -> SelectAllNavigationLabelButton? { + guard let controller = self.delegate?.moleculeDelegate as? PageProtocol, + let rightNavButtonModels = controller.pageModel?.navigationBar?.additionalRightButtons + else { return nil } + + var navButton: SelectAllNavigationLabelButton? = nil + + for navModel in rightNavButtonModels { + if let model = navModel as? SelectAllNavigationLabelButton { + navButton = model + } + } + + return navButton + } + /// In the event that the user manually selects or deselects all `SelectableMoleculeModel` /// the behavior will need to reflect the inverse of its previously expected action. /// Initiates the navigation and page behavior realignment - /// - Parameter asSelectAll: The actual value didSelectAllState ought to be. - func realignPageBehavior(asSelectAll: Bool) { - didSelectAllState = asSelectAll + /// - Parameter asSelectAll: The actual value willSelectAllState ought to be. + func realignPageBehaviorAs(willSelectAll: Bool) { + willSelectAllState = willSelectAll updatePageNavigationUI() } /// Updates the navigation UI to correctly reflect the behavior's state. func updatePageNavigationUI() { - guard let model = model as? SelectAllBoxesBehaviorModel else { return } - -// let navButtonTitle: String? = didSelectAllState ? model.deselectAllTitle : model.selectAllTitle - // TODO: update - -// MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in -// guard let controller = self?.delegate?.moleculeDelegate as? PageProtocol else { return } -// controller.handleNewDataAndUpdateUI() -// let n = controller.getNavigationModel() -// let r = n?.additionalRightButtons -// for i in r! { -// i.moleculeName -// } -// }) + MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in + (self?.delegate?.moleculeDelegate as? ViewController)?.handleNewDataAndUpdateUI() + }) } /// Convenience function for readability to confirmt he state of the behavior. - /// - Returns: Boolean indicating that the behavior's `didSelectAllState` is false while all model values are true (selected). + /// - Returns: Boolean indicating that the behavior's `willSelectAllState` is false while all model values are true (selected). func selectAllIsMisaligned() -> Bool { - !didSelectAllState && valuesMirror.values.allSatisfy { $0 == true } + willSelectAllState && valuesMirror.values.allSatisfy { $0 == true } } /// Convenience function for readability to confirmt he state of the behavior. - /// - Returns: Boolean indicating that the behavior's `didSelectAllState` is true while all model values are false (deselected). + /// - Returns: Boolean indicating that the behavior's `willSelectAllState` is true while all model values are false (deselected). func deselectAllIsMisaligned() -> Bool { - didSelectAllState && valuesMirror.values.allSatisfy { $0 == false } + !willSelectAllState && valuesMirror.values.allSatisfy { $0 == false } } /// Convenience function making it easier to read if a current selectable model should be acted on. /// - Parameter model: A model object assined to the SelectableModel protocol /// - Returns: Boolean determining if the passed model should be selected. func toSelect(model: SelectableMoleculeModelProtocol) -> Bool { - didSelectAllState && !model.selected + willSelectAllState && !model.selected } /// Convenience function making it easier to read if a current selectable model should be acted on. /// - Parameter model: A model object assined to the SelectableModel protocol /// - Returns: Boolean determining if the passed model should be deselected. func toDeselect(model: SelectableMoleculeModelProtocol) -> Bool { - !didSelectAllState && model.selected + !willSelectAllState && model.selected } } From ada936eff64f28e884a734c17f780a5331c32fff Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Mon, 28 Jun 2021 22:39:22 +0530 Subject: [PATCH 21/44] Comments update --- MVMCoreUI/Behaviors/PlayAudioBehavior.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/MVMCoreUI/Behaviors/PlayAudioBehavior.swift b/MVMCoreUI/Behaviors/PlayAudioBehavior.swift index b555eb01..4775d131 100644 --- a/MVMCoreUI/Behaviors/PlayAudioBehavior.swift +++ b/MVMCoreUI/Behaviors/PlayAudioBehavior.swift @@ -53,7 +53,6 @@ public class PagePlayAudioBehavior: PageCustomActionHandlerBehavior { public func handleAction(type actionType: String?, information: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) -> Bool { guard actionType == "playAudio" else { return false } - // TODO: Impose Activity Indicator. // Update the model. play -> pause OR pause -> play if Self.activeAudioPlayerDelegate?.isPlaying ?? false { @@ -62,9 +61,6 @@ public class PagePlayAudioBehavior: PageCustomActionHandlerBehavior { } else { Self.activeAudioPlayerDelegate?.play() } - - // TODO: Tell Template to update this cell (needs to be built). Currently it updates all cells. - return true } From f8dce8503b95212ae8d6c84f67a97e7c3cc2c432 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 29 Jun 2021 13:11:40 -0400 Subject: [PATCH 22/44] changed behavior to align with android. --- .../Atoms/Selectors/CheckboxModel.swift | 12 ++- .../Atomic/Atoms/Selectors/ToggleModel.swift | 4 +- .../Behaviors/SelectAllBoxesBehavior.swift | 89 +++++++++---------- 3 files changed, 52 insertions(+), 53 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift index 87c4568d..31f19bae 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift @@ -7,7 +7,7 @@ // -@objcMembers public class CheckboxModel: NSObject, MoleculeModelProtocol, SelectableMoleculeModelProtocol, FormFieldProtocol { +@objcMembers public class CheckboxModel: MoleculeModelProtocol, SelectableMoleculeModelProtocol, FormFieldProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -15,7 +15,7 @@ public static var identifier: String = "checkbox" public var backgroundColor: Color? public var accessibilityIdentifier: String? - public dynamic var selected: Bool = false + public var selected: Bool = false public var enabled: Bool = true public var animated: Bool = true public var inverted: Bool = false @@ -80,6 +80,14 @@ baseValue = isChecked } + //-------------------------------------------------- + // MARK: - Behavior + //-------------------------------------------------- + + public func getRequiredBehaviors() -> [PageBehaviorModelProtocol] { + [SelectAllBoxesBehaviorModel()] + } + //-------------------------------------------------- // MARK: - Codec //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift index 0fb42632..056035b4 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift @@ -7,7 +7,7 @@ // -public class ToggleModel: NSObject, MoleculeModelProtocol, FormFieldProtocol, EnableableModelProtocol, SelectableMoleculeModelProtocol { +public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableModelProtocol, SelectableMoleculeModelProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -15,7 +15,7 @@ public class ToggleModel: NSObject, MoleculeModelProtocol, FormFieldProtocol, En public static var identifier: String = "toggle" public var accessibilityIdentifier: String? public var backgroundColor: Color? - public dynamic var selected: Bool = false + public var selected: Bool = false public var animated: Bool = true public var enabled: Bool = true public var action: ActionModelProtocol? diff --git a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift index 1f7326fd..3837eaa9 100644 --- a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift +++ b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift @@ -9,8 +9,8 @@ /// Protocol to apply to any model of a UI Control with a binary on/off nature. /// /// Example classes: Checkbox or Toggle. -@objc public protocol SelectableMoleculeModelProtocol: AnyObject { - @objc dynamic var selected: Bool { get set } +@objc public protocol SelectableMoleculeModelProtocol { + var selected: Bool { get set } } public class SelectAllBoxesBehaviorModel: PageBehaviorModelProtocol { @@ -34,9 +34,6 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior, PageMolecu /// Reference to the general PageBehaviorModel. var model: PageBehaviorModelProtocol - /// Dictionary of KVOs to observing the selected property of each `SelectableMoleculeModel`. - private var observers = [String: NSKeyValueObservation?]() - /// A store representing the values of the `SelectableMoleculeModel`. private var valuesMirror = [String: Bool]() @@ -57,45 +54,17 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior, PageMolecu public func onPageNew(rootMolecules: [MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject) { - let selectableModels: [(NSObject & SelectableMoleculeModelProtocol)] = rootMolecules.allMoleculesOfType() + let selectableModels: [SelectableMoleculeModelProtocol] = rootMolecules.allMoleculesOfType() guard !selectableModels.isEmpty else { return } for model in selectableModels { if let key = (model as? FormFieldProtocol)?.fieldKey { valuesMirror[key] = model.selected - setObserver(model, fieldKey: key) } } } - func setObserver(_ model: T, fieldKey: String) where T: (NSObject & SelectableMoleculeModelProtocol) { - - observers[fieldKey] = model.observe(\.selected, options: [.new]) { [weak self] model, change in - guard let self = self, - let isChecked = change.newValue - else { return } - - self.valuesMirror[fieldKey] = isChecked - - // If all are models are in the opposite state of the behavior, then realign. - if self.selectAllIsMisaligned() { - self.realignPageBehaviorAs(willSelectAll: false) - - } else if self.deselectAllIsMisaligned() { - self.realignPageBehaviorAs(willSelectAll: true) - } - } - } - - //-------------------------------------------------- - // MARK: - Deinit - //-------------------------------------------------- - - deinit { - observers.values.forEach { $0?.invalidate() } - } - //-------------------------------------------------- // MARK: - Custom Action //-------------------------------------------------- @@ -110,23 +79,45 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior, PageMolecu public func handleAction(type actionType: String?, information: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) -> Bool { // Verify we have the correct action type and necessary values. - guard actionType == "selectAllBoxes", - let selectableModels: [SelectableMoleculeModelProtocol] = delegate?.moleculeDelegate?.getRootMolecules().allMoleculesOfType(), - !selectableModels.isEmpty - else { return false } - - // Hold value dues to asynch behavior of page refreshing. - let newSelectedState = willSelectAllState - - // Iterate through selectable molecules. - for selectableModel in selectableModels { - if toSelect(model: selectableModel) || toDeselect(model: selectableModel) { - selectableModel.selected = newSelectedState + if actionType == "selectAllBoxes" { + guard let selectableModels: [SelectableMoleculeModelProtocol] = delegate?.moleculeDelegate?.getRootMolecules().allMoleculesOfType(), + !selectableModels.isEmpty + else { return false } + + // Hold value dues to asynch behavior of page refreshing. + let newSelectedState = willSelectAllState + + // Iterate through selectable molecules. + for selectableModel in selectableModels { + if toSelect(model: selectableModel) || toDeselect(model: selectableModel) { + selectableModel.selected = newSelectedState + } } + + willSelectAllState.toggle() + updatePageNavigationUI() + return true + + } else if actionType == "boxSelected" { + guard let checkboxModel = (additionalData?["sourceModel"] as? CheckboxModel), + let fieldKey = checkboxModel.fieldKey + else { return false } + + self.valuesMirror[fieldKey] = checkboxModel.selected + + // If all are models are in the opposite state of the behavior, then realign. + if self.selectAllIsMisaligned() { + self.realignPageBehaviorAs(willSelectAll: false) + + } else if self.deselectAllIsMisaligned() { + self.realignPageBehaviorAs(willSelectAll: true) + } + + return true + + } else { + return false } - - updatePageNavigationUI() - return true } //-------------------------------------------------- From 7566d9365936973fcc0d0fc863bebb589322f135 Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Wed, 30 Jun 2021 18:51:41 +0530 Subject: [PATCH 23/44] Registering PlayAudio, SelectAllBoxes behaviors --- MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift index 5cf71a75..be621811 100644 --- a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift +++ b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift @@ -222,6 +222,8 @@ open class CoreUIModelMapping: ModelMapping { open class func registerBehaviors() { ModelRegistry.register(handler: ScreenBrightnessModifierBehavior.self, for: ScreenBrightnessModifierBehaviorModel.self) ModelRegistry.register(handler: PageGetContactBehavior.self, for: PageGetContactBehaviorModel.self) + ModelRegistry.register(handler: PagePlayAudioBehavior.self, for: PagePlayAudioBehaviorModel.self) + ModelRegistry.register(handler: SelectAllBoxesBehavior.self, for: SelectAllBoxesBehaviorModel.self) } open override class func registerActions() { From 495eb1d4bd2838f06ade6f4500c7600249986187 Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Thu, 1 Jul 2021 11:56:12 +0530 Subject: [PATCH 24/44] Making ListLeftVariableIconWithRightCaretBodyTextModel class open to subclass --- .../ListLeftVariableIconWithRightCaretBodyTextModel.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift index 5076eb9e..9e93b01d 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift @@ -7,12 +7,12 @@ // -public class ListLeftVariableIconWithRightCaretBodyTextModel: ListItemModel, MoleculeModelProtocol { +open class ListLeftVariableIconWithRightCaretBodyTextModel: ListItemModel, MoleculeModelProtocol { //----------------------------------------------------- // MARK: - Properties //----------------------------------------------------- - public static var identifier: String = "listLVImgBdy" + open class var identifier: String { return "listLVImgBdy" } public var image: ImageViewModel public var headlineBody: HeadlineBodyModel public var rightLabel: LabelModel From 56fa3f71c05ce08ad141a4e8928e350f0f8118c9 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 6 Jul 2021 14:16:48 -0400 Subject: [PATCH 25/44] updates made. --- MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift index 5cf71a75..00c58668 100644 --- a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift +++ b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift @@ -222,6 +222,7 @@ open class CoreUIModelMapping: ModelMapping { open class func registerBehaviors() { ModelRegistry.register(handler: ScreenBrightnessModifierBehavior.self, for: ScreenBrightnessModifierBehaviorModel.self) ModelRegistry.register(handler: PageGetContactBehavior.self, for: PageGetContactBehaviorModel.self) + ModelRegistry.register(handler: SelectAllBoxesBehavior.self, for: SelectAllBoxesBehaviorModel.self) } open override class func registerActions() { From 1b8f13117db9e2093505e1a9506c5be9e4748f3a Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Thu, 8 Jul 2021 13:36:09 +0530 Subject: [PATCH 26/44] Changes to read contacts using Contact behavior --- MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift | 2 +- .../ListLeftVariableIconWithRightCaretBodyTextModel.swift | 6 +++++- .../ListRightVariableRightCaretAlltextAndLinksModel.swift | 6 +++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift index 5cc07fed..2eec132f 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift @@ -81,7 +81,7 @@ numberOfLines = try typeContainer.decodeIfPresent(Int.self, forKey: .numberOfLines) } - public func encode(to encoder: Encoder) throws { + open func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encodeIfPresent(moleculeName, forKey: .moleculeName) try container.encode(text, forKey: .text) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift index 9e93b01d..6a84fee0 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift @@ -7,7 +7,7 @@ // -open class ListLeftVariableIconWithRightCaretBodyTextModel: ListItemModel, MoleculeModelProtocol { +open class ListLeftVariableIconWithRightCaretBodyTextModel: ListItemModel, ParentMoleculeModelProtocol { //----------------------------------------------------- // MARK: - Properties //----------------------------------------------------- @@ -17,6 +17,10 @@ open class ListLeftVariableIconWithRightCaretBodyTextModel: ListItemModel, Molec public var headlineBody: HeadlineBodyModel public var rightLabel: LabelModel + public var children: [MoleculeModelProtocol] { + return [image, headlineBody,rightLabel] + } + //----------------------------------------------------- // MARK: - Methods //----------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableRightCaretAlltextAndLinksModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableRightCaretAlltextAndLinksModel.swift index f16daf2b..54bf3162 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableRightCaretAlltextAndLinksModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableRightCaretAlltextAndLinksModel.swift @@ -7,7 +7,7 @@ // -public class ListRightVariableRightCaretAllTextAndLinksModel: ListItemModel, MoleculeModelProtocol { +public class ListRightVariableRightCaretAllTextAndLinksModel: ListItemModel, ParentMoleculeModelProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -16,6 +16,10 @@ public class ListRightVariableRightCaretAllTextAndLinksModel: ListItemModel, Mol public var rightLabel: LabelModel public var eyebrowHeadlineBodyLink: EyebrowHeadlineBodyLinkModel + public var children: [MoleculeModelProtocol] { + return [rightLabel, eyebrowHeadlineBodyLink] + } + //----------------------------------------------------- // MARK: - Methods //----------------------------------------------------- From bb10fdf818dc699741649e842e4ace21b4cf058a Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Mon, 12 Jul 2021 11:50:38 +0530 Subject: [PATCH 27/44] Changes are per review comments --- .../ListLeftVariableIconWithRightCaretBodyTextModel.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift index 6a84fee0..88eec8ea 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift @@ -7,18 +7,18 @@ // -open class ListLeftVariableIconWithRightCaretBodyTextModel: ListItemModel, ParentMoleculeModelProtocol { +public class ListLeftVariableIconWithRightCaretBodyTextModel: ListItemModel, MoleculeModelProtocol { //----------------------------------------------------- // MARK: - Properties //----------------------------------------------------- - open class var identifier: String { return "listLVImgBdy" } + public static var identifier: String = "listLVImgBdy" public var image: ImageViewModel public var headlineBody: HeadlineBodyModel public var rightLabel: LabelModel public var children: [MoleculeModelProtocol] { - return [image, headlineBody,rightLabel] + return [image, headlineBody, rightLabel] } //----------------------------------------------------- From f74372c56ed124926d9f338231f06165b4dc63f0 Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Mon, 12 Jul 2021 20:07:50 +0530 Subject: [PATCH 28/44] Changes are per review comments --- .../ListLeftVariableIconWithRightCaretBodyTextModel.swift | 2 +- MVMCoreUI/Behaviors/PlayAudioBehavior.swift | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift index 88eec8ea..33e00982 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift @@ -7,7 +7,7 @@ // -public class ListLeftVariableIconWithRightCaretBodyTextModel: ListItemModel, MoleculeModelProtocol { +public class ListLeftVariableIconWithRightCaretBodyTextModel: ListItemModel, ParentMoleculeModelProtocol { //----------------------------------------------------- // MARK: - Properties //----------------------------------------------------- diff --git a/MVMCoreUI/Behaviors/PlayAudioBehavior.swift b/MVMCoreUI/Behaviors/PlayAudioBehavior.swift index 4775d131..12a98022 100644 --- a/MVMCoreUI/Behaviors/PlayAudioBehavior.swift +++ b/MVMCoreUI/Behaviors/PlayAudioBehavior.swift @@ -29,13 +29,13 @@ public class PagePlayAudioBehavior: PageCustomActionHandlerBehavior { // MARK: - Active Model //-------------------------------------------------- - public static var activeAudioPlayerDelegate: PagePlayAudioBehaviorConsumerProtocol? + public static var activeAudioPlayerDelegate: PagePlayAudioBehaviorConsumerProtocol? //-------------------------------------------------- // MARK: - Delegate //-------------------------------------------------- - var delegate: MVMCoreUIDelegateObject? + weak var delegate: MVMCoreUIDelegateObject? //-------------------------------------------------- // MARK: - Init @@ -57,7 +57,6 @@ public class PagePlayAudioBehavior: PageCustomActionHandlerBehavior { // Update the model. play -> pause OR pause -> play if Self.activeAudioPlayerDelegate?.isPlaying ?? false { Self.activeAudioPlayerDelegate?.pause() - } else { Self.activeAudioPlayerDelegate?.play() } @@ -65,6 +64,7 @@ public class PagePlayAudioBehavior: PageCustomActionHandlerBehavior { } public func onPageHidden(_ delegateObject: MVMCoreUIDelegateObject?) { - // TODO: Stop player + //Stop player + Self.activeAudioPlayerDelegate?.pause() } } From 4d46d56f8e89717441735421df4553efdb3ab93e Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 12 Jul 2021 14:44:26 -0400 Subject: [PATCH 29/44] updates --- MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift | 10 +--------- .../Behaviors/Protocols/PageBehaviorProtocol.swift | 5 +++++ MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift | 10 ++-------- 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift index 31f19bae..12330ada 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift @@ -79,15 +79,7 @@ self.selected = isChecked baseValue = isChecked } - - //-------------------------------------------------- - // MARK: - Behavior - //-------------------------------------------------- - - public func getRequiredBehaviors() -> [PageBehaviorModelProtocol] { - [SelectAllBoxesBehaviorModel()] - } - + //-------------------------------------------------- // MARK: - Codec //-------------------------------------------------- diff --git a/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift b/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift index e7db54bc..3f14f3cc 100644 --- a/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift +++ b/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift @@ -41,6 +41,11 @@ public protocol PageLocalDataShareBehavior: PageBehaviorProtocol { public protocol PageCustomActionHandlerBehavior: PageBehaviorProtocol { + /// - Parameters: + /// - actionType: The action type of the passed action model. + /// - information: information of the passed action model. + /// - additionalData: Additional information of the + /// - Returns: Boolean determines if the action has been handled. func handleAction(type actionType: String?, information: [AnyHashable : Any]?, additionalData: [AnyHashable : Any]?) -> Bool } diff --git a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift index 3837eaa9..3877bfd1 100644 --- a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift +++ b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift @@ -41,7 +41,7 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior, PageMolecu // MARK: - Delegate //-------------------------------------------------- - var delegate: MVMCoreUIDelegateObject? + weak var delegate: MVMCoreUIDelegateObject? //-------------------------------------------------- // MARK: - Init @@ -69,13 +69,7 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior, PageMolecu // MARK: - Custom Action //-------------------------------------------------- - /// To select or deselect all controls adhereing to `SelectableMoleculeModel` - /// - /// - Parameters: - /// - actionType: The action type of the passed action model. - /// - information: information of the passed action model. - /// - additionalData: Additional information of the - /// - Returns: Boolean determines if the action has been handled. + // To select or deselect all controls adhereing to `SelectableMoleculeModel` public func handleAction(type actionType: String?, information: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) -> Bool { // Verify we have the correct action type and necessary values. From f434ba3e8d764fec676add585e654d6a8e21b081 Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Tue, 13 Jul 2021 00:20:02 +0530 Subject: [PATCH 30/44] Confirming to Visibility behavior --- MVMCoreUI/Behaviors/PlayAudioBehavior.swift | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/MVMCoreUI/Behaviors/PlayAudioBehavior.swift b/MVMCoreUI/Behaviors/PlayAudioBehavior.swift index 12a98022..ebb9f46c 100644 --- a/MVMCoreUI/Behaviors/PlayAudioBehavior.swift +++ b/MVMCoreUI/Behaviors/PlayAudioBehavior.swift @@ -24,7 +24,8 @@ public class PagePlayAudioBehaviorModel: PageBehaviorModelProtocol { public init() { } } -public class PagePlayAudioBehavior: PageCustomActionHandlerBehavior { +public class PagePlayAudioBehavior: PageCustomActionHandlerBehavior, PageVisibilityBehavior { + //-------------------------------------------------- // MARK: - Active Model //-------------------------------------------------- @@ -63,6 +64,12 @@ public class PagePlayAudioBehavior: PageCustomActionHandlerBehavior { return true } + //-------------------------------------------------- + // MARK: - PageVisibilityBehavior + //-------------------------------------------------- + + public func onPageShown(_ delegateObject: MVMCoreUIDelegateObject?) { } + public func onPageHidden(_ delegateObject: MVMCoreUIDelegateObject?) { //Stop player Self.activeAudioPlayerDelegate?.pause() From aaef3ea224f00d9285552207103df3458f70c04a Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 12 Jul 2021 16:06:24 -0400 Subject: [PATCH 31/44] move files --- MVMCoreUI.xcodeproj/project.pbxproj | 8 - .../Atoms/Selectors/CheckboxModel.swift | 8 +- .../Atomic/Atoms/Selectors/ToggleModel.swift | 2 +- .../SelectAllNavigationLabelButton.swift | 82 -------- .../Behaviors/SelectAllBoxesBehavior.swift | 178 ------------------ .../OtherHandlers/CoreUIModelMapping.swift | 2 - 6 files changed, 8 insertions(+), 272 deletions(-) delete mode 100644 MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/SelectAllNavigationLabelButton.swift delete mode 100644 MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index ef9b278f..9d145d5a 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -74,7 +74,6 @@ 0A25209824645B76000FA9F6 /* TextViewEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A25209724645B76000FA9F6 /* TextViewEntryFieldModel.swift */; }; 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */; }; 0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */; }; - 0A423A202684E7A0008EC258 /* SelectAllNavigationLabelButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A423A1F2684E7A0008EC258 /* SelectAllNavigationLabelButton.swift */; }; 0A51F3E22475CB73002E08B6 /* LoadingSpinnerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A51F3E02475CB73002E08B6 /* LoadingSpinnerModel.swift */; }; 0A51F3E32475CB73002E08B6 /* LoadingSpinner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A51F3E12475CB73002E08B6 /* LoadingSpinner.swift */; }; 0A5D59C223AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */; }; @@ -109,7 +108,6 @@ 0A9D09222433796500D2E6C0 /* CarouselIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A9D091C2433796500D2E6C0 /* CarouselIndicator.swift */; }; 0AA33B3A2398524F0067DD0F /* Toggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AA33B392398524F0067DD0F /* Toggle.swift */; }; 0AA4D2E125CAEC72008DB32D /* AccessibilityModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AA4D2E025CAEC72008DB32D /* AccessibilityModelProtocol.swift */; }; - 0AAB7855267B86F900DD6437 /* SelectAllBoxesBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AAB7854267B86F900DD6437 /* SelectAllBoxesBehavior.swift */; }; 0AB000BA24BF63490090C5E7 /* ModalListPageTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB000B924BF63490090C5E7 /* ModalListPageTemplateModel.swift */; }; 0AB000BC24BF64A50090C5E7 /* ModalStackPageTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB000BB24BF64A50090C5E7 /* ModalStackPageTemplateModel.swift */; }; 0AB764D124460F6300E7FE72 /* UIDatePicker+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB764D024460F6300E7FE72 /* UIDatePicker+Extension.swift */; }; @@ -639,7 +637,6 @@ 0A25209724645B76000FA9F6 /* TextViewEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewEntryFieldModel.swift; sourceTree = ""; }; 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CATransaction+Extension.swift"; sourceTree = ""; }; 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEntryField.swift; sourceTree = ""; }; - 0A423A1F2684E7A0008EC258 /* SelectAllNavigationLabelButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectAllNavigationLabelButton.swift; sourceTree = ""; }; 0A51F3E02475CB73002E08B6 /* LoadingSpinnerModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadingSpinnerModel.swift; sourceTree = ""; }; 0A51F3E12475CB73002E08B6 /* LoadingSpinner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadingSpinner.swift; sourceTree = ""; }; 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleGuidelinesProtocol.swift; sourceTree = ""; }; @@ -678,7 +675,6 @@ 0AA33B33239813C50067DD0F /* UIColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Extension.swift"; sourceTree = ""; }; 0AA33B392398524F0067DD0F /* Toggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toggle.swift; sourceTree = ""; }; 0AA4D2E025CAEC72008DB32D /* AccessibilityModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityModelProtocol.swift; sourceTree = ""; }; - 0AAB7854267B86F900DD6437 /* SelectAllBoxesBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectAllBoxesBehavior.swift; sourceTree = ""; }; 0AB000B924BF63490090C5E7 /* ModalListPageTemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalListPageTemplateModel.swift; sourceTree = ""; }; 0AB000BB24BF64A50090C5E7 /* ModalStackPageTemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalStackPageTemplateModel.swift; sourceTree = ""; }; 0AB764D024460F6300E7FE72 /* UIDatePicker+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDatePicker+Extension.swift"; sourceTree = ""; }; @@ -1324,7 +1320,6 @@ 27F97369246750BE00CAB5C5 /* ScreenBrightnessModifierBehavior.swift */, D23A900826125FFB007E14CE /* GetContactBehavior.swift */, 0A01DE262626236300C2CAAC /* PlayAudioBehavior.swift */, - 0AAB7854267B86F900DD6437 /* SelectAllBoxesBehavior.swift */, ); path = Behaviors; sourceTree = ""; @@ -1763,7 +1758,6 @@ D23EA801247EBED400D60C34 /* ImageBarButtonItem.swift */, D23EA7FD247EBBB700D60C34 /* NavigationLabelButtonModel.swift */, D23EA7FF247EBD6C00D60C34 /* LabelBarButtonItem.swift */, - 0A423A1F2684E7A0008EC258 /* SelectAllNavigationLabelButton.swift */, ); path = Buttons; sourceTree = ""; @@ -2727,7 +2721,6 @@ 011D959B240451E3000E3791 /* RuleRequiredModel.swift in Sources */, 526A265C240D1FF700B0D828 /* ListTwoColumnCompareChangesModel.swift in Sources */, D2A92886241ACD99004E01C6 /* ProgrammaticTableViewController.swift in Sources */, - 0AAB7855267B86F900DD6437 /* SelectAllBoxesBehavior.swift in Sources */, BBAA4F05243D8E3B005AAD5F /* RadioBoxesModel.swift in Sources */, 01509D952327ED1900EF99AA /* HeadlineBodyLinkToggle.swift in Sources */, AA104ADA244734DB004D2810 /* HeadersH1LandingPageHeader.swift in Sources */, @@ -2739,7 +2732,6 @@ D264FA8E243BCD9A00D98315 /* CollectionTemplate.swift in Sources */, 0A7EF85B23D8A52800B2AAD1 /* EntryFieldModel.swift in Sources */, AA633B3124989EC000731E80 /* HeadersH2PricingTwoRowsModel.swift in Sources */, - 0A423A202684E7A0008EC258 /* SelectAllNavigationLabelButton.swift in Sources */, 8DEFA95C243DAC20000D27E5 /* ListThreeColumnDataUsageDividerModel.swift in Sources */, D2092357244FA1EF0044AD09 /* ThreeLayerModelBase.swift in Sources */, D2FD4A4925199BD9000C28A9 /* AccessibilityProtocol.swift in Sources */, diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift index 12330ada..c4f69f27 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift @@ -6,6 +6,12 @@ // Copyright © 2020 Verizon Wireless. All rights reserved. // +/// Protocol to apply to any model of a UI Control with a binary on/off nature. +/// +/// Example classes: Checkbox or Toggle. +@objc public protocol SelectableMoleculeModelProtocol { + var selected: Bool { get set } +} @objcMembers public class CheckboxModel: MoleculeModelProtocol, SelectableMoleculeModelProtocol, FormFieldProtocol { //-------------------------------------------------- @@ -79,7 +85,7 @@ self.selected = isChecked baseValue = isChecked } - + //-------------------------------------------------- // MARK: - Codec //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift index 056035b4..5be014fb 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift @@ -7,7 +7,7 @@ // -public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableModelProtocol, SelectableMoleculeModelProtocol { +public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableModelProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/SelectAllNavigationLabelButton.swift b/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/SelectAllNavigationLabelButton.swift deleted file mode 100644 index 59bf6136..00000000 --- a/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/SelectAllNavigationLabelButton.swift +++ /dev/null @@ -1,82 +0,0 @@ -// -// SelectAllNavigationLabelButton.swift -// MVMCoreUI -// -// Created by Kevin Christiano on 6/24/21. -// Copyright © 2021 Verizon Wireless. All rights reserved. -// - - -public class SelectAllNavigationLabelButton: NavigationButtonModelProtocol, MoleculeModelProtocol { - //-------------------------------------------------- - // MARK: - Properties - //-------------------------------------------------- - - public var backgroundColor: Color? - public static var identifier: String = "selectAllNavigationLabelButton" - public var accessibilityIdentifier: String? - public var willSelect: Bool = true - public var selectAllTitle: String = "Select All" - public var deselectAllTitle: String = "Deselect All" - public var action: ActionModelProtocol - - public var selectionTitle: String { - willSelect ? selectAllTitle : deselectAllTitle - } - - //-------------------------------------------------- - // MARK: - Initializer - //-------------------------------------------------- - - public init(willSelect: Bool, selectAllTitle: String, deselectAllTitle: String, action: ActionModelProtocol) { - self.willSelect = willSelect - self.action = action - self.selectAllTitle = selectAllTitle - self.deselectAllTitle = deselectAllTitle - } - - //-------------------------------------------------- - // MARK: - Keys - //-------------------------------------------------- - - private enum CodingKeys: String, CodingKey { - case moleculeName - case accessibilityIdentifier - case willSelect - case selectAllTitle - case deSelectAllTitle - case action - } - - //-------------------------------------------------- - // MARK: - Codec - //-------------------------------------------------- - - required public init(from decoder: Decoder) throws { - let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier) - selectAllTitle = try typeContainer.decode(String.self, forKey: .selectAllTitle) - deselectAllTitle = try typeContainer.decode(String.self, forKey: .deSelectAllTitle) - willSelect = try typeContainer.decode(Bool.self, forKey: .willSelect) - action = try typeContainer.decodeModel(codingKey: .action) - } - - open func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(moleculeName, forKey: .moleculeName) - try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier) - try container.encode(selectAllTitle, forKey: .selectAllTitle) - try container.encode(deselectAllTitle, forKey: .deSelectAllTitle) - try container.encode(willSelect, forKey: .willSelect) - try container.encodeModel(action, forKey: .action) - } - - //-------------------------------------------------- - // MARK: - Methods - //-------------------------------------------------- - - /// Convenience function that creates a BarButtonItem for the model. - public func createNavigationItemButton(delegateObject: MVMCoreUIDelegateObject? = nil, additionalData: [AnyHashable: Any]? = nil) -> UIBarButtonItem { - LabelBarButtonItem.create(with: selectionTitle, actionModel: action, delegateObject: delegateObject, additionalData: additionalData) - } -} diff --git a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift deleted file mode 100644 index 3877bfd1..00000000 --- a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift +++ /dev/null @@ -1,178 +0,0 @@ -// -// SelectAllBoxesBehavior.swift -// MVMCoreUI -// -// Created by Kevin Christiano on 6/17/21. -// Copyright © 2021 Verizon Wireless. All rights reserved. -// - -/// Protocol to apply to any model of a UI Control with a binary on/off nature. -/// -/// Example classes: Checkbox or Toggle. -@objc public protocol SelectableMoleculeModelProtocol { - var selected: Bool { get set } -} - -public class SelectAllBoxesBehaviorModel: PageBehaviorModelProtocol { - public class var identifier: String { "pageSelectAllBoxesBehavior" } - public var shouldAllowMultipleInstances: Bool { false } - public init() { } -} - -/// Selects all the control models presented on a page. -public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior, PageMoleculeTransformationBehavior { - //-------------------------------------------------- - // MARK: - Properties - //-------------------------------------------------- - - /// Status of the select all behavior. Initially false as the action has not been enaged. - var willSelectAllState: Bool { - get { getSelectAllNavbutton()?.willSelect ?? false } - set { getSelectAllNavbutton()?.willSelect = newValue } - } - - /// Reference to the general PageBehaviorModel. - var model: PageBehaviorModelProtocol - - /// A store representing the values of the `SelectableMoleculeModel`. - private var valuesMirror = [String: Bool]() - - //-------------------------------------------------- - // MARK: - Delegate - //-------------------------------------------------- - - weak var delegate: MVMCoreUIDelegateObject? - - //-------------------------------------------------- - // MARK: - Init - //-------------------------------------------------- - - required public init(model: PageBehaviorModelProtocol, delegateObject: MVMCoreUIDelegateObject?) { - self.model = model - self.delegate = delegateObject - } - - public func onPageNew(rootMolecules: [MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject) { - - let selectableModels: [SelectableMoleculeModelProtocol] = rootMolecules.allMoleculesOfType() - - guard !selectableModels.isEmpty else { return } - - for model in selectableModels { - if let key = (model as? FormFieldProtocol)?.fieldKey { - valuesMirror[key] = model.selected - } - } - } - - //-------------------------------------------------- - // MARK: - Custom Action - //-------------------------------------------------- - - // To select or deselect all controls adhereing to `SelectableMoleculeModel` - public func handleAction(type actionType: String?, information: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) -> Bool { - - // Verify we have the correct action type and necessary values. - if actionType == "selectAllBoxes" { - guard let selectableModels: [SelectableMoleculeModelProtocol] = delegate?.moleculeDelegate?.getRootMolecules().allMoleculesOfType(), - !selectableModels.isEmpty - else { return false } - - // Hold value dues to asynch behavior of page refreshing. - let newSelectedState = willSelectAllState - - // Iterate through selectable molecules. - for selectableModel in selectableModels { - if toSelect(model: selectableModel) || toDeselect(model: selectableModel) { - selectableModel.selected = newSelectedState - } - } - - willSelectAllState.toggle() - updatePageNavigationUI() - return true - - } else if actionType == "boxSelected" { - guard let checkboxModel = (additionalData?["sourceModel"] as? CheckboxModel), - let fieldKey = checkboxModel.fieldKey - else { return false } - - self.valuesMirror[fieldKey] = checkboxModel.selected - - // If all are models are in the opposite state of the behavior, then realign. - if self.selectAllIsMisaligned() { - self.realignPageBehaviorAs(willSelectAll: false) - - } else if self.deselectAllIsMisaligned() { - self.realignPageBehaviorAs(willSelectAll: true) - } - - return true - - } else { - return false - } - } - - //-------------------------------------------------- - // MARK: - Methods - //-------------------------------------------------- - - func getSelectAllNavbutton() -> SelectAllNavigationLabelButton? { - guard let controller = self.delegate?.moleculeDelegate as? PageProtocol, - let rightNavButtonModels = controller.pageModel?.navigationBar?.additionalRightButtons - else { return nil } - - var navButton: SelectAllNavigationLabelButton? = nil - - for navModel in rightNavButtonModels { - if let model = navModel as? SelectAllNavigationLabelButton { - navButton = model - } - } - - return navButton - } - - /// In the event that the user manually selects or deselects all `SelectableMoleculeModel` - /// the behavior will need to reflect the inverse of its previously expected action. - /// Initiates the navigation and page behavior realignment - /// - Parameter asSelectAll: The actual value willSelectAllState ought to be. - func realignPageBehaviorAs(willSelectAll: Bool) { - willSelectAllState = willSelectAll - updatePageNavigationUI() - } - - /// Updates the navigation UI to correctly reflect the behavior's state. - func updatePageNavigationUI() { - MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in - (self?.delegate?.moleculeDelegate as? ViewController)?.handleNewDataAndUpdateUI() - }) - } - - /// Convenience function for readability to confirmt he state of the behavior. - /// - Returns: Boolean indicating that the behavior's `willSelectAllState` is false while all model values are true (selected). - func selectAllIsMisaligned() -> Bool { - willSelectAllState && valuesMirror.values.allSatisfy { $0 == true } - } - - /// Convenience function for readability to confirmt he state of the behavior. - /// - Returns: Boolean indicating that the behavior's `willSelectAllState` is true while all model values are false (deselected). - func deselectAllIsMisaligned() -> Bool { - !willSelectAllState && valuesMirror.values.allSatisfy { $0 == false } - } - - /// Convenience function making it easier to read if a current selectable model should be acted on. - /// - Parameter model: A model object assined to the SelectableModel protocol - /// - Returns: Boolean determining if the passed model should be selected. - func toSelect(model: SelectableMoleculeModelProtocol) -> Bool { - willSelectAllState && !model.selected - } - - /// Convenience function making it easier to read if a current selectable model should be acted on. - /// - Parameter model: A model object assined to the SelectableModel protocol - /// - Returns: Boolean determining if the passed model should be deselected. - func toDeselect(model: SelectableMoleculeModelProtocol) -> Bool { - !willSelectAllState && model.selected - } -} diff --git a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift index 3fc511f3..c95964b2 100644 --- a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift +++ b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift @@ -127,7 +127,6 @@ open class CoreUIModelMapping: ModelMapping { ModelRegistry.register(NavigationItemModel.self) ModelRegistry.register(NavigationImageButtonModel.self) ModelRegistry.register(NavigationLabelButtonModel.self) - ModelRegistry.register(SelectAllNavigationLabelButton.self) // MARK:- Other Organisms ModelRegistry.register(handler: Carousel.self, for: CarouselModel.self) @@ -224,7 +223,6 @@ open class CoreUIModelMapping: ModelMapping { ModelRegistry.register(handler: ScreenBrightnessModifierBehavior.self, for: ScreenBrightnessModifierBehaviorModel.self) ModelRegistry.register(handler: PageGetContactBehavior.self, for: PageGetContactBehaviorModel.self) ModelRegistry.register(handler: PagePlayAudioBehavior.self, for: PagePlayAudioBehaviorModel.self) - ModelRegistry.register(handler: SelectAllBoxesBehavior.self, for: SelectAllBoxesBehaviorModel.self) } open override class func registerActions() { From edbe68429b0d791dde49f365ce7dc4710b0a1a77 Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Wed, 14 Jul 2021 00:19:00 +0530 Subject: [PATCH 32/44] Moving PlayAudioBehavior to MobileFirst --- MVMCoreUI.xcodeproj/project.pbxproj | 4 - MVMCoreUI/Behaviors/PlayAudioBehavior.swift | 77 ------------------- .../OtherHandlers/CoreUIModelMapping.swift | 1 - 3 files changed, 82 deletions(-) delete mode 100644 MVMCoreUI/Behaviors/PlayAudioBehavior.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 9d145d5a..15f22974 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -61,7 +61,6 @@ 01EB369323609801006832FA /* HeaderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368C23609801006832FA /* HeaderModel.swift */; }; 01EB369423609801006832FA /* HeadlineBodyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368D23609801006832FA /* HeadlineBodyModel.swift */; }; 01F2A03223A4498200D954D8 /* CaretLinkModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2A03123A4498200D954D8 /* CaretLinkModel.swift */; }; - 0A01DE272626236300C2CAAC /* PlayAudioBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A01DE262626236300C2CAAC /* PlayAudioBehavior.swift */; }; 0A0FEC7425D42A5E00AF2548 /* BaseItemPickerEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A0FEC7325D42A5E00AF2548 /* BaseItemPickerEntryField.swift */; }; 0A0FEC7825D42A8500AF2548 /* BaseItemPickerEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A0FEC7725D42A8500AF2548 /* BaseItemPickerEntryFieldModel.swift */; }; 0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */; }; @@ -625,7 +624,6 @@ 01EB368C23609801006832FA /* HeaderModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderModel.swift; sourceTree = ""; }; 01EB368D23609801006832FA /* HeadlineBodyModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeadlineBodyModel.swift; sourceTree = ""; }; 01F2A03123A4498200D954D8 /* CaretLinkModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaretLinkModel.swift; sourceTree = ""; }; - 0A01DE262626236300C2CAAC /* PlayAudioBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayAudioBehavior.swift; sourceTree = ""; }; 0A0FEC7325D42A5E00AF2548 /* BaseItemPickerEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseItemPickerEntryField.swift; sourceTree = ""; }; 0A0FEC7725D42A8500AF2548 /* BaseItemPickerEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseItemPickerEntryFieldModel.swift; sourceTree = ""; }; 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionDetailWithImage.swift; sourceTree = ""; }; @@ -1319,7 +1317,6 @@ 0A1C30972620F61A00B47F3B /* Protocols */, 27F97369246750BE00CAB5C5 /* ScreenBrightnessModifierBehavior.swift */, D23A900826125FFB007E14CE /* GetContactBehavior.swift */, - 0A01DE262626236300C2CAAC /* PlayAudioBehavior.swift */, ); path = Behaviors; sourceTree = ""; @@ -2886,7 +2883,6 @@ D2092355244FA0FD0044AD09 /* ThreeLayerTemplateModelProtocol.swift in Sources */, 0AE14F64238315D2005417F8 /* TextField.swift in Sources */, 0A51F3E22475CB73002E08B6 /* LoadingSpinnerModel.swift in Sources */, - 0A01DE272626236300C2CAAC /* PlayAudioBehavior.swift in Sources */, D2169303251E53D9002A6324 /* SectionListTemplateModel.swift in Sources */, 0AB764D124460F6300E7FE72 /* UIDatePicker+Extension.swift in Sources */, BB105859248DEFF70069D008 /* UICollectionViewLeftAlignedLayout.swift in Sources */, diff --git a/MVMCoreUI/Behaviors/PlayAudioBehavior.swift b/MVMCoreUI/Behaviors/PlayAudioBehavior.swift deleted file mode 100644 index ebb9f46c..00000000 --- a/MVMCoreUI/Behaviors/PlayAudioBehavior.swift +++ /dev/null @@ -1,77 +0,0 @@ -// -// PlayAudioBehavior.swift -// MVMCoreUI -// -// Created by Kevin Christiano on 4/9/21. -// Copyright © 2021 Verizon Wireless. All rights reserved. -// - - -public protocol PagePlayAudioBehaviorConsumerProtocol { - func togglePlayPause() - func play() - func pause() - func stop() - var isPlaying: Bool { get } - var messageID: String? { get } - var audioFileURL: URL? { get set } -} - -public class PagePlayAudioBehaviorModel: PageBehaviorModelProtocol { - public class var identifier: String { "pagePlayAudioBehavior" } - public var shouldAllowMultipleInstances: Bool { false } - - public init() { } -} - -public class PagePlayAudioBehavior: PageCustomActionHandlerBehavior, PageVisibilityBehavior { - - //-------------------------------------------------- - // MARK: - Active Model - //-------------------------------------------------- - - public static var activeAudioPlayerDelegate: PagePlayAudioBehaviorConsumerProtocol? - - //-------------------------------------------------- - // MARK: - Delegate - //-------------------------------------------------- - - weak var delegate: MVMCoreUIDelegateObject? - - //-------------------------------------------------- - // MARK: - Init - //-------------------------------------------------- - - public required init(model: PageBehaviorModelProtocol, delegateObject: MVMCoreUIDelegateObject?) { - self.delegate = delegateObject - } - - //-------------------------------------------------- - // MARK: - Custom Action - //-------------------------------------------------- - - // Either play or pause - public func handleAction(type actionType: String?, information: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) -> Bool { - - guard actionType == "playAudio" else { return false } - - // Update the model. play -> pause OR pause -> play - if Self.activeAudioPlayerDelegate?.isPlaying ?? false { - Self.activeAudioPlayerDelegate?.pause() - } else { - Self.activeAudioPlayerDelegate?.play() - } - return true - } - - //-------------------------------------------------- - // MARK: - PageVisibilityBehavior - //-------------------------------------------------- - - public func onPageShown(_ delegateObject: MVMCoreUIDelegateObject?) { } - - public func onPageHidden(_ delegateObject: MVMCoreUIDelegateObject?) { - //Stop player - Self.activeAudioPlayerDelegate?.pause() - } -} diff --git a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift index c95964b2..1edea27b 100644 --- a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift +++ b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift @@ -222,7 +222,6 @@ open class CoreUIModelMapping: ModelMapping { open class func registerBehaviors() { ModelRegistry.register(handler: ScreenBrightnessModifierBehavior.self, for: ScreenBrightnessModifierBehaviorModel.self) ModelRegistry.register(handler: PageGetContactBehavior.self, for: PageGetContactBehaviorModel.self) - ModelRegistry.register(handler: PagePlayAudioBehavior.self, for: PagePlayAudioBehaviorModel.self) } open override class func registerActions() { From 3af89dfdc64ce5102fb401cbe739fae0e1cdc62a Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Fri, 16 Jul 2021 02:14:56 +0530 Subject: [PATCH 33/44] Changes in CornerLabelModel to dynamically pick molecule's model --- .../LeftRightViews/CornerLabelsModel.swift | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/LeftRightViews/CornerLabelsModel.swift b/MVMCoreUI/Atomic/Molecules/LeftRightViews/CornerLabelsModel.swift index 76a56178..58b661c6 100644 --- a/MVMCoreUI/Atomic/Molecules/LeftRightViews/CornerLabelsModel.swift +++ b/MVMCoreUI/Atomic/Molecules/LeftRightViews/CornerLabelsModel.swift @@ -8,7 +8,7 @@ import UIKit -public class CornerLabelsModel: MoleculeModelProtocol { +public class CornerLabelsModel: ParentMoleculeModelProtocol { public static var identifier: String = "cornerLabels" public var backgroundColor: Color? public var topLeftLabel: LabelModel? @@ -16,7 +16,10 @@ public class CornerLabelsModel: MoleculeModelProtocol { public var bottomLeftLabel: LabelModel? public var bottomRightLabel: LabelModel? public var molecule: MoleculeModelProtocol? - + public var children: [MoleculeModelProtocol] { + return [topLeftLabel, topRightLabel, bottomLeftLabel, bottomRightLabel].compactMap { (molecule: MoleculeModelProtocol?) in molecule } + } + init(with molecule: MoleculeModelProtocol?) { self.molecule = molecule } @@ -35,20 +38,20 @@ public class CornerLabelsModel: MoleculeModelProtocol { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) molecule = try typeContainer.decodeModelIfPresent(codingKey: .molecule) - topLeftLabel = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .topLeftLabel) - topRightLabel = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .topRightLabel) - bottomLeftLabel = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .bottomLeftLabel) - bottomRightLabel = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .bottomRightLabel) + topLeftLabel = try typeContainer.decodeMoleculeIfPresent(codingKey: .topLeftLabel) + topRightLabel = try typeContainer.decodeMoleculeIfPresent(codingKey: .topRightLabel) + bottomLeftLabel = try typeContainer.decodeMoleculeIfPresent(codingKey: .bottomLeftLabel) + bottomRightLabel = try typeContainer.decodeMoleculeIfPresent(codingKey: .bottomRightLabel) } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) try container.encodeModelIfPresent(molecule, forKey: .molecule) - try container.encodeIfPresent(topLeftLabel, forKey: .topLeftLabel) - try container.encodeIfPresent(topRightLabel, forKey: .topRightLabel) - try container.encodeIfPresent(bottomLeftLabel, forKey: .bottomLeftLabel) - try container.encodeIfPresent(bottomRightLabel, forKey: .bottomRightLabel) + try container.encodeModelIfPresent(topLeftLabel, forKey: .topLeftLabel) + try container.encodeModelIfPresent(topRightLabel, forKey: .topRightLabel) + try container.encodeModelIfPresent(bottomLeftLabel, forKey: .bottomLeftLabel) + try container.encodeModelIfPresent(bottomRightLabel, forKey: .bottomRightLabel) try container.encode(moleculeName, forKey: .moleculeName) } } From 0c7a4bf62ce428eaa3477d95ad2986a8ae512985 Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Fri, 16 Jul 2021 03:05:06 +0530 Subject: [PATCH 34/44] Fixing moleculeLayoutUpdate for tableView --- MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift index 34f81bc4..32c4f1f2 100644 --- a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift @@ -185,7 +185,8 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol open override func moleculeLayoutUpdated(_ molecule: MoleculeViewProtocol) { guard let tableView = tableView else { return } - let point = molecule.convert(molecule.bounds.origin, to: tableView) + var point = molecule.convert(molecule.bounds.origin, to: tableView) + point = CGPoint(x: ceil(point.x), y: ceil(point.y)) if let indexPath = tableView.indexPathForRow(at: point), tableView.indexPathsForVisibleRows?.contains(indexPath) ?? false { performTableViewUpdates() } From 52a872f95dedf7806b43b2ecf15fc9cd59c5f156 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Fri, 16 Jul 2021 17:37:55 -0400 Subject: [PATCH 35/44] child molecule fixes --- ...iableIconWithRightCaretBodyTextModel.swift | 2 +- .../NavigationBar/NavigationItemModel.swift | 22 +++++++++++++++++++ .../Templates/StackPageTemplateModel.swift | 2 +- .../Templates/ThreeLayerModelBase.swift | 2 +- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift index 33e00982..633989d5 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift @@ -18,7 +18,7 @@ public class ListLeftVariableIconWithRightCaretBodyTextModel: ListItemModel, Par public var rightLabel: LabelModel public var children: [MoleculeModelProtocol] { - return [image, headlineBody, rightLabel] + [image, headlineBody, rightLabel] } //----------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Molecules/NavigationBar/NavigationItemModel.swift b/MVMCoreUI/Atomic/Molecules/NavigationBar/NavigationItemModel.swift index 5fab61f9..5f3db6be 100644 --- a/MVMCoreUI/Atomic/Molecules/NavigationBar/NavigationItemModel.swift +++ b/MVMCoreUI/Atomic/Molecules/NavigationBar/NavigationItemModel.swift @@ -91,3 +91,25 @@ open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtoc try container.encodeModelIfPresent(titleView, forKey: .titleView) } } + +extension NavigationItemModel: ParentMoleculeModelProtocol { + public var children: [MoleculeModelProtocol] { + var children: [MoleculeModelProtocol] = [] + if let line = line { + children.append(line) + } + if let titleView = titleView { + children.append(titleView) + } + if let backButton = backButton { + children.append(backButton) + } + if let leftButtons = additionalLeftButtons { + children.append(contentsOf: leftButtons) + } + if let rightButtons = additionalRightButtons { + children.append(contentsOf: rightButtons) + } + return children + } +} diff --git a/MVMCoreUI/Atomic/Templates/StackPageTemplateModel.swift b/MVMCoreUI/Atomic/Templates/StackPageTemplateModel.swift index 27769b20..1ed663c2 100644 --- a/MVMCoreUI/Atomic/Templates/StackPageTemplateModel.swift +++ b/MVMCoreUI/Atomic/Templates/StackPageTemplateModel.swift @@ -16,7 +16,7 @@ public var moleculeStack: StackModel public override var rootMolecules: [MoleculeModelProtocol] { - return [header, moleculeStack, footer].compactMap { $0 } + [navigationBar, header, moleculeStack, footer].compactMap { $0 } } //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Templates/ThreeLayerModelBase.swift b/MVMCoreUI/Atomic/Templates/ThreeLayerModelBase.swift index 6a1bb244..06d813ef 100644 --- a/MVMCoreUI/Atomic/Templates/ThreeLayerModelBase.swift +++ b/MVMCoreUI/Atomic/Templates/ThreeLayerModelBase.swift @@ -18,7 +18,7 @@ public var footer: MoleculeModelProtocol? public override var rootMolecules: [MoleculeModelProtocol] { - return [header, footer].compactMap { $0 } + [navigationBar, header, footer].compactMap { $0 } } //-------------------------------------------------- From b75f25764f866607decfb608ecd23fa5049bac77 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Fri, 16 Jul 2021 17:59:19 -0400 Subject: [PATCH 36/44] cleanup --- .../Molecules/LeftRightViews/CornerLabelsModel.swift | 2 +- .../Molecules/NavigationBar/NavigationItemModel.swift | 11 +---------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/LeftRightViews/CornerLabelsModel.swift b/MVMCoreUI/Atomic/Molecules/LeftRightViews/CornerLabelsModel.swift index 58b661c6..5c910298 100644 --- a/MVMCoreUI/Atomic/Molecules/LeftRightViews/CornerLabelsModel.swift +++ b/MVMCoreUI/Atomic/Molecules/LeftRightViews/CornerLabelsModel.swift @@ -17,7 +17,7 @@ public class CornerLabelsModel: ParentMoleculeModelProtocol { public var bottomRightLabel: LabelModel? public var molecule: MoleculeModelProtocol? public var children: [MoleculeModelProtocol] { - return [topLeftLabel, topRightLabel, bottomLeftLabel, bottomRightLabel].compactMap { (molecule: MoleculeModelProtocol?) in molecule } + [molecule, topLeftLabel, topRightLabel, bottomLeftLabel, bottomRightLabel].compactMap { $0 } } init(with molecule: MoleculeModelProtocol?) { diff --git a/MVMCoreUI/Atomic/Molecules/NavigationBar/NavigationItemModel.swift b/MVMCoreUI/Atomic/Molecules/NavigationBar/NavigationItemModel.swift index 5f3db6be..6a75718b 100644 --- a/MVMCoreUI/Atomic/Molecules/NavigationBar/NavigationItemModel.swift +++ b/MVMCoreUI/Atomic/Molecules/NavigationBar/NavigationItemModel.swift @@ -94,16 +94,7 @@ open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtoc extension NavigationItemModel: ParentMoleculeModelProtocol { public var children: [MoleculeModelProtocol] { - var children: [MoleculeModelProtocol] = [] - if let line = line { - children.append(line) - } - if let titleView = titleView { - children.append(titleView) - } - if let backButton = backButton { - children.append(backButton) - } + var children: [MoleculeModelProtocol] = [line, titleView, backButton].compactMap { $0 } if let leftButtons = additionalLeftButtons { children.append(contentsOf: leftButtons) } From ccf583615e2c22094997cbd36788ad6f654a66b0 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Fri, 16 Jul 2021 18:00:44 -0400 Subject: [PATCH 37/44] cleanup --- .../ListRightVariableRightCaretAlltextAndLinksModel.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableRightCaretAlltextAndLinksModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableRightCaretAlltextAndLinksModel.swift index 54bf3162..e2bc1691 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableRightCaretAlltextAndLinksModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableRightCaretAlltextAndLinksModel.swift @@ -17,7 +17,7 @@ public class ListRightVariableRightCaretAllTextAndLinksModel: ListItemModel, Par public var eyebrowHeadlineBodyLink: EyebrowHeadlineBodyLinkModel public var children: [MoleculeModelProtocol] { - return [rightLabel, eyebrowHeadlineBodyLink] + [rightLabel, eyebrowHeadlineBodyLink] } //----------------------------------------------------- From bcf810d5cb6e4b3dc3e73858206bc62892da3435 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Fri, 16 Jul 2021 18:12:04 -0400 Subject: [PATCH 38/44] chang to just use a different point --- MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift index 32c4f1f2..a1c2d3b6 100644 --- a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift @@ -185,8 +185,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol open override func moleculeLayoutUpdated(_ molecule: MoleculeViewProtocol) { guard let tableView = tableView else { return } - var point = molecule.convert(molecule.bounds.origin, to: tableView) - point = CGPoint(x: ceil(point.x), y: ceil(point.y)) + let point = molecule.convert(molecule.center, to: tableView) if let indexPath = tableView.indexPathForRow(at: point), tableView.indexPathsForVisibleRows?.contains(indexPath) ?? false { performTableViewUpdates() } From d00897cf75246de769d36fa6ca4d68446c307843 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Fri, 16 Jul 2021 20:54:33 -0400 Subject: [PATCH 39/44] navigation bar changes --- .../Buttons/ImageBarButtonItem.swift | 11 ++--------- .../Buttons/LabelBarButtonItem.swift | 11 ++--------- .../Buttons/NavigationImageButtonModel.swift | 2 +- .../Buttons/NavigationLabelButtonModel.swift | 16 ++++++++-------- MVMCoreUI/BaseClasses/BarButtonItem.swift | 16 +++++----------- 5 files changed, 18 insertions(+), 38 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/ImageBarButtonItem.swift b/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/ImageBarButtonItem.swift index 33ed39b8..50676cbc 100644 --- a/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/ImageBarButtonItem.swift +++ b/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/ImageBarButtonItem.swift @@ -20,16 +20,9 @@ } /// Creates the item with the passed in action. - public static func create(with image: UIImage?, actionModel: ActionModelProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Self { + public static func create(with image: UIImage?, model: MoleculeModelProtocol & NavigationButtonModelProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Self { let button = create(with: image) - button.set(with: actionModel, delegateObject: delegateObject, additionalData: additionalData) - return button - } - - /// Creates the item with the passed in action map. - public static func create(with image: UIImage?, actionMap: [AnyHashable: Any], delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Self { - let button = create(with: image) - button.set(with: actionMap, delegateObject: delegateObject, additionalData: additionalData) + button.set(with: model, delegateObject: delegateObject, additionalData: additionalData) return button } diff --git a/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/LabelBarButtonItem.swift b/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/LabelBarButtonItem.swift index 5175defe..1eb4c8a1 100644 --- a/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/LabelBarButtonItem.swift +++ b/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/LabelBarButtonItem.swift @@ -21,16 +21,9 @@ } /// Creates the item with the passed in action. - public static func create(with title: String?, actionModel: ActionModelProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Self { + public static func create(with title: String?, model: NavigationLabelButtonModel, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Self { let button = create(with: title) - button.set(with: actionModel, delegateObject: delegateObject, additionalData: additionalData) - return button - } - - /// Creates the item with the passed in action map. - public static func create(with title: String?, actionMap: [AnyHashable : Any], delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Self { - let button = create(with: title) - button.set(with: actionMap, delegateObject: delegateObject, additionalData: additionalData) + button.set(with: model, delegateObject: delegateObject, additionalData: additionalData) return button } diff --git a/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/NavigationImageButtonModel.swift b/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/NavigationImageButtonModel.swift index f18c9fa1..8ba75d1a 100644 --- a/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/NavigationImageButtonModel.swift +++ b/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/NavigationImageButtonModel.swift @@ -67,7 +67,7 @@ public class NavigationImageButtonModel: NavigationButtonModelProtocol, Molecule /// Convenience function that creates a BarButtonItem for the model. public func createNavigationItemButton(delegateObject: MVMCoreUIDelegateObject? = nil, additionalData: [AnyHashable: Any]? = nil) -> UIBarButtonItem { let uiImage = MVMCoreCache.shared()?.getImageFromRegisteredBundles(image) - let buttonItem = ImageBarButtonItem.create(with: uiImage, actionModel: action, delegateObject: delegateObject, additionalData: additionalData) + let buttonItem = ImageBarButtonItem.create(with: uiImage, model: self, delegateObject: delegateObject, additionalData: additionalData) buttonItem.accessibilityIdentifier = accessibilityIdentifier ?? image if let accessibilityString = accessibilityText { buttonItem.accessibilityLabel = accessibilityString diff --git a/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/NavigationLabelButtonModel.swift b/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/NavigationLabelButtonModel.swift index e52ea0d5..d72c6ae0 100644 --- a/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/NavigationLabelButtonModel.swift +++ b/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/NavigationLabelButtonModel.swift @@ -7,16 +7,16 @@ // -public class NavigationLabelButtonModel: NavigationButtonModelProtocol, MoleculeModelProtocol { +open class NavigationLabelButtonModel: NavigationButtonModelProtocol, MoleculeModelProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- - public var backgroundColor: Color? - public static var identifier: String = "navigationLabelButton" - public var accessibilityIdentifier: String? - public var title: String - public var action: ActionModelProtocol + open var backgroundColor: Color? + open class var identifier: String { "navigationLabelButton" } + open var accessibilityIdentifier: String? + open var title: String + open var action: ActionModelProtocol //-------------------------------------------------- // MARK: - Initializer @@ -62,7 +62,7 @@ public class NavigationLabelButtonModel: NavigationButtonModelProtocol, Molecule //-------------------------------------------------- /// Convenience function that creates a BarButtonItem for the model. - public func createNavigationItemButton(delegateObject: MVMCoreUIDelegateObject? = nil, additionalData: [AnyHashable: Any]? = nil) -> UIBarButtonItem { - return LabelBarButtonItem.create(with: title, actionModel: action, delegateObject: delegateObject, additionalData: additionalData) + open func createNavigationItemButton(delegateObject: MVMCoreUIDelegateObject? = nil, additionalData: [AnyHashable: Any]? = nil) -> UIBarButtonItem { + return LabelBarButtonItem.create(with: title, model: self, delegateObject: delegateObject, additionalData: additionalData) } } diff --git a/MVMCoreUI/BaseClasses/BarButtonItem.swift b/MVMCoreUI/BaseClasses/BarButtonItem.swift index d41fd57f..b46647f2 100644 --- a/MVMCoreUI/BaseClasses/BarButtonItem.swift +++ b/MVMCoreUI/BaseClasses/BarButtonItem.swift @@ -20,7 +20,7 @@ public typealias BarButtonAction = (BarButtonItem) -> () //-------------------------------------------------- // MARK: - Delegate //-------------------------------------------------- - + open var model: (MoleculeModelProtocol & NavigationButtonModelProtocol)? open weak var buttonDelegate: ButtonDelegateProtocol? var actionDelegate: ActionDelegate? @@ -28,18 +28,12 @@ public typealias BarButtonAction = (BarButtonItem) -> () // MARK: - Methods //-------------------------------------------------- - open func set(with actionModel: ActionModelProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + open func set(with model: MoleculeModelProtocol & NavigationButtonModelProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + self.model = model buttonDelegate = delegateObject?.buttonDelegate actionDelegate?.buttonAction = { sender in - Button.performButtonAction(with: actionModel, button: sender, delegateObject: delegateObject, additionalData: additionalData) - } - } - - open func set(with actionMap: [AnyHashable : Any], delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - buttonDelegate = delegateObject?.buttonDelegate - actionDelegate?.buttonAction = { sender in - guard delegateObject?.buttonDelegate?.button?(sender, shouldPerformActionWithMap: actionMap, additionalData: additionalData) ?? true else { return } - MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) + let additionalDataWithSource = additionalData.dictionaryAdding(key: KeySourceModel, value: model) + Button.performButtonAction(with: model.action, button: sender, delegateObject: delegateObject, additionalData: additionalDataWithSource) } } } From 350edf147c62c5b7f188649c12832774d69b115a Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Tue, 20 Jul 2021 07:56:23 +0530 Subject: [PATCH 40/44] update view for given molecule --- .../Templates/MoleculeListTemplate.swift | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift index a1c2d3b6..dc86aa4d 100644 --- a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift @@ -222,6 +222,33 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol } } + open func newData(for molecule: MoleculeModelProtocol) { + //TODO: expand for header, navigation, etc + let json = molecule.toJSON() + guard let index = moleculesInfo?.firstIndex(where: { (moleculeInfo) -> Bool in + //TODO: check for molecule protocol eqaulity + if json == moleculeInfo.molecule.toJSON() { + return true + } else if let parent = moleculeInfo.molecule as? ParentMoleculeModelProtocol { + // Get all molecules of the same type for faster check. + let molecules: [MoleculeModelProtocol] = parent.reduceDepthFirstTraverse(options: .childFirst, depth: 0, initialResult: []) { (accumulator, currentMolecule, depth) in + if currentMolecule.moleculeName == molecule.moleculeName { + return accumulator + [currentMolecule] + } + return accumulator + } + for molecule in molecules { + if json == molecule.toJSON() { + return true + } + } + } + return false + }) else { return } + let indexPath = IndexPath(row: index, section: 0) + tableView.reloadRows(at: [indexPath], with: .none) + } + open override func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], animation: UITableView.RowAnimation) { var indexPaths: [IndexPath] = [] //TODO: check for molecule protocol equality From f0c567d6d47821d9710d214b7cd1e5b21c41cddb Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 20 Jul 2021 00:57:34 -0400 Subject: [PATCH 41/44] fixes --- .../Templates/MoleculeListTemplate.swift | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift index dc86aa4d..c12b74fa 100644 --- a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift @@ -183,10 +183,8 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol //-------------------------------------------------- open override func moleculeLayoutUpdated(_ molecule: MoleculeViewProtocol) { - guard let tableView = tableView else { return } - - let point = molecule.convert(molecule.center, to: tableView) - if let indexPath = tableView.indexPathForRow(at: point), tableView.indexPathsForVisibleRows?.contains(indexPath) ?? false { + guard let tableView = tableView else { return } + if let indexPath = tableView.indexPathForRow(at: molecule.center), tableView.indexPathsForVisibleRows?.contains(indexPath) ?? false { performTableViewUpdates() } } @@ -226,25 +224,27 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol //TODO: expand for header, navigation, etc let json = molecule.toJSON() guard let index = moleculesInfo?.firstIndex(where: { (moleculeInfo) -> Bool in - //TODO: check for molecule protocol eqaulity - if json == moleculeInfo.molecule.toJSON() { - return true - } else if let parent = moleculeInfo.molecule as? ParentMoleculeModelProtocol { - // Get all molecules of the same type for faster check. - let molecules: [MoleculeModelProtocol] = parent.reduceDepthFirstTraverse(options: .childFirst, depth: 0, initialResult: []) { (accumulator, currentMolecule, depth) in - if currentMolecule.moleculeName == molecule.moleculeName { - return accumulator + [currentMolecule] - } - return accumulator - } - for molecule in molecules { - if json == molecule.toJSON() { + //TODO: check for molecule protocol eqaulity + if json == moleculeInfo.molecule.toJSON() { return true - } + } else if let parent = moleculeInfo.molecule as? ParentMoleculeModelProtocol { + // Get all molecules of the same type for faster check. + let molecules: [MoleculeModelProtocol] = parent.reduceDepthFirstTraverse(options: .childFirst, depth: 0, initialResult: []) { (accumulator, currentMolecule, depth) in + if currentMolecule.moleculeName == molecule.moleculeName { + return accumulator + [currentMolecule] + } + return accumulator + } + for molecule in molecules { + if json == molecule.toJSON() { + return true + } + } } - } - return false + return false }) else { return } + + // Refresh the cell. let indexPath = IndexPath(row: index, section: 0) tableView.reloadRows(at: [indexPath], with: .none) } From 9a477a11a06cb02363df778bb41d5441c284c397 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 20 Jul 2021 01:13:35 -0400 Subject: [PATCH 42/44] teemporary fix for unselect issues --- MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift index c12b74fa..baab7479 100644 --- a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift @@ -246,8 +246,9 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol // Refresh the cell. let indexPath = IndexPath(row: index, section: 0) - tableView.reloadRows(at: [indexPath], with: .none) - } + _ = tableView(tableView, cellForRowAt: indexPath) + performTableViewUpdates() + } open override func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], animation: UITableView.RowAnimation) { var indexPaths: [IndexPath] = [] From d244c38921020e7262e97471ae4d3f646e67fb18 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 20 Jul 2021 13:38:04 -0400 Subject: [PATCH 43/44] revert for ui --- MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift index baab7479..d5c7de98 100644 --- a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift @@ -246,8 +246,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol // Refresh the cell. let indexPath = IndexPath(row: index, section: 0) - _ = tableView(tableView, cellForRowAt: indexPath) - performTableViewUpdates() + tableView.reloadRows(at: [indexPath], with: .automatic) } open override func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], animation: UITableView.RowAnimation) { From cfad9aae27f11d1f4432b5a2ed8fa8c89ca7aa2f Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 20 Jul 2021 13:47:08 -0400 Subject: [PATCH 44/44] selection update --- MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift index d5c7de98..de79cec3 100644 --- a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift @@ -244,9 +244,13 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol return false }) else { return } - // Refresh the cell. + // Refresh the cell. (reload loses cell selection) + let selectedIndex = tableView.indexPathForSelectedRow let indexPath = IndexPath(row: index, section: 0) tableView.reloadRows(at: [indexPath], with: .automatic) + if let selectedIndex = selectedIndex { + tableView.selectRow(at: selectedIndex, animated: false, scrollPosition: .none) + } } open override func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], animation: UITableView.RowAnimation) {