diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 68a2fa0c..3fce1455 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -235,6 +235,8 @@ AA71AD4024A32FE700ACA76F /* HeadersH2Link.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA71AD3F24A32FE700ACA76F /* HeadersH2Link.swift */; }; AA7F32AB246C0F7900C965BA /* ListLeftVariableRadioButtonAllTextAndLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA7F32AA246C0F7900C965BA /* ListLeftVariableRadioButtonAllTextAndLinksModel.swift */; }; AA7F32AD246C0F8C00C965BA /* ListLeftVariableRadioButtonAllTextAndLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA7F32AC246C0F8C00C965BA /* ListLeftVariableRadioButtonAllTextAndLinks.swift */; }; + AA7F47732541AD560015A2C1 /* ListStarRatingModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA7F47722541AD560015A2C1 /* ListStarRatingModel.swift */; }; + AA7F47762541AD6A0015A2C1 /* ListStarRating.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA7F47752541AD6A0015A2C1 /* ListStarRating.swift */; }; AA85236C244435A20059CC1E /* RadioSwatchCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA85236B244435A20059CC1E /* RadioSwatchCollectionViewCell.swift */; }; AA9972502475309F00FC7472 /* ListLeftVariableIconAllTextLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA99724F2475309F00FC7472 /* ListLeftVariableIconAllTextLinksModel.swift */; }; AA997252247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA997251247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift */; }; @@ -776,6 +778,8 @@ AA71AD3F24A32FE700ACA76F /* HeadersH2Link.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2Link.swift; sourceTree = ""; }; AA7F32AA246C0F7900C965BA /* ListLeftVariableRadioButtonAllTextAndLinksModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableRadioButtonAllTextAndLinksModel.swift; sourceTree = ""; }; AA7F32AC246C0F8C00C965BA /* ListLeftVariableRadioButtonAllTextAndLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableRadioButtonAllTextAndLinks.swift; sourceTree = ""; }; + AA7F47722541AD560015A2C1 /* ListStarRatingModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListStarRatingModel.swift; sourceTree = ""; }; + AA7F47752541AD6A0015A2C1 /* ListStarRating.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListStarRating.swift; sourceTree = ""; }; AA85236B244435A20059CC1E /* RadioSwatchCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatchCollectionViewCell.swift; sourceTree = ""; }; AA99724F2475309F00FC7472 /* ListLeftVariableIconAllTextLinksModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableIconAllTextLinksModel.swift; sourceTree = ""; }; AA997251247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableIconAllTextLinks.swift; sourceTree = ""; }; @@ -1363,6 +1367,8 @@ children = ( AAE96FA125341F6A0037A989 /* ListStoreLocatorModel.swift */, AAE96FA425341F7D0037A989 /* ListStoreLocator.swift */, + AA7F47722541AD560015A2C1 /* ListStarRatingModel.swift */, + AA7F47752541AD6A0015A2C1 /* ListStarRating.swift */, ); path = Miscellaneous; sourceTree = ""; @@ -2661,6 +2667,8 @@ 011B58F023A2AA980085F53C /* ListItemModelProtocol.swift in Sources */, D22479962316AF6E003FCCF9 /* HeadlineBodyLink.swift in Sources */, 8DE5BECD2456F7A200772E76 /* ListTwoColumnDropdownSelectorsModel.swift in Sources */, + AA7F47732541AD560015A2C1 /* ListStarRatingModel.swift in Sources */, + AA7F47762541AD6A0015A2C1 /* ListStarRating.swift in Sources */, 0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */, D2ED27EB254B0CE700A1C293 /* UIAlertActionStyle+Codable.swift in Sources */, BB55B51D244482C1002001AD /* ListRightVariablePriceChangeBodyText.swift in Sources */, diff --git a/MVMCoreUI/Alerts/MVMCoreAlertHandler+Extension.swift b/MVMCoreUI/Alerts/MVMCoreAlertHandler+Extension.swift index 309ea8f5..b0158e2d 100644 --- a/MVMCoreUI/Alerts/MVMCoreAlertHandler+Extension.swift +++ b/MVMCoreUI/Alerts/MVMCoreAlertHandler+Extension.swift @@ -8,88 +8,60 @@ import Foundation -// Temporary, until we can move page checking logic into isReady of topAlertOperation. -@objcMembers public class NotificationPagesOperation: Operation { - public let pages: [String] - - public init(with pages: [String]) { - self.pages = pages +public extension MVMCoreAlertHandler { + + /// Re-evaluates the queue operations + @objc func reevaluteQueue() { + var highestReadyOperation: MVMCoreTopAlertOperation? + var executingOperation: MVMCoreTopAlertOperation? + for case let operation as MVMCoreTopAlertOperation in topAlertQueue.operations { + guard !operation.isCancelled, + !operation.isFinished else { continue } + if operation.isReady, + highestReadyOperation == nil || operation.queuePriority.rawValue > highestReadyOperation!.queuePriority.rawValue { + highestReadyOperation = operation + } + if operation.isExecuting { + executingOperation = operation + } + } + guard let currentOperation = executingOperation else { return } + + // Cancel the executing operation if it is no longer ready to run. Re-add for later if it is persistent. + guard currentOperation.isReady else { + currentOperation.reAddAfterCancel = currentOperation.topAlertObject.persistent + currentOperation.cancel() + return + } + + // If the highest priority operation is not executing, and the executing operation is persistent, cancel it. + if let newOperation = highestReadyOperation, + currentOperation != newOperation, + currentOperation.topAlertObject.persistent { + currentOperation.reAddAfterCancel = true + currentOperation.cancel() + } } - public override var isReady: Bool { - get { - return super.isReady && isCancelled - } + /// Registers to know when pages change. + @objc func registerForPageChanges() { + MVMCoreNavigationHandler.shared()?.addDelegate(self) } } -// TODO: Move this type of logic into isReady for the top alert operation... then can remove this dependency operation. -public extension MVMCoreAlertHandler { - - /// Adds a page type dependency to the operation - @objc func addPagesDependency(to operation: MVMCoreTopAlertOperation) { - // This notification may only show for certain pages. - guard let pages = operation.topAlertObject.json?.optionalArrayForKey("pages") as? [String], - pages.count > 0 else { return } - let pagesOperation = NotificationPagesOperation(with: pages) - pageOperations.addOperation(pagesOperation) - operation.addDependency(pagesOperation) - } - - /// Updates the pages requirement for the operation - @objc func updatePages(for operation: MVMCoreTopAlertOperation, with topAlertObject: MVMCoreTopAlertObject) { - // Add new dependencies, remove old. - let previousPages = operation.dependencies.filter { $0 as? NotificationPagesOperation != nil } - addPagesDependency(to: operation) - for pageOperation in previousPages { - pageOperation.cancel() - operation.removeDependency(pageOperation) - } - } - - /// Handles page dependencies for all top alerts with the new pageType - @objc func handleAllPagesDependency(for pageType: String?) { - var currentOperation: MVMCoreTopAlertOperation? = nil - for case let operation as MVMCoreTopAlertOperation in topAlertQueue.operations { - // Handle the currently executing opration last to avoid race conditions. - guard !operation.isExecuting else { - currentOperation = operation - continue - } - handlePageDependency(for: operation, with: pageType) - } - if let operation = currentOperation { - handlePageDependency(for: operation, with: pageType) - } - } - - /// Updates the operation based on the page type and its dependencies. - @objc func handlePageDependency(for operation: MVMCoreTopAlertOperation, with pageType: String?) { - guard !operation.isCancelled else { return } - - if let pages = operation.topAlertObject.json?.optionalArrayForKey("pages") as? [String], - pages.count > 0, - (pageType == nil || !pages.contains(pageType!)) { - if let dependency = operation.dependencies.first(where: { $0.isFinished && ($0 as? NotificationPagesOperation)?.pages == pages }) { - // Re-add the dependency if it was previously cancelled. - let pagesOperation = NotificationPagesOperation(with: pages) - pageOperations.addOperation(pagesOperation) - operation.addDependency(pagesOperation) - operation.removeDependency(dependency) - } - if operation.isExecuting { - // If the current running operation should not show on the current page, cancel it. If it's persistent, re-add it - operation.reAddAfterCancel = operation.topAlertObject.persistent - operation.cancel() - } - } - - // Cancel any dependency if it contains the current page. - guard let pageType = pageType else { return } - for case let operation as NotificationPagesOperation in operation.dependencies { - if operation.pages.contains(pageType) { - operation.cancel() - } +extension MVMCoreAlertHandler: MVMCorePresentationDelegateProtocol { + // Update displayable for each top alert operation when page type changes, in top queue priority order. + public func navigationController(_ navigationController: UINavigationController, displayedViewController viewController: UIViewController) { + guard navigationController == MVMCoreUISplitViewController.main()?.navigationController else { return } + let pageType = (viewController as? MVMCoreViewControllerProtocol)?.pageType + topAlertQueue.operations.compactMap { + $0 as? MVMCoreTopAlertOperation + }.sorted { + $0.queuePriority.rawValue > $1.queuePriority.rawValue + }.forEach { + $0.updateDisplayable(byPageType: pageType) } + reevaluteQueue() } } + diff --git a/MVMCoreUI/Alerts/MVMCoreAlertHandler.h b/MVMCoreUI/Alerts/MVMCoreAlertHandler.h index f3b30efd..522c5740 100644 --- a/MVMCoreUI/Alerts/MVMCoreAlertHandler.h +++ b/MVMCoreUI/Alerts/MVMCoreAlertHandler.h @@ -23,9 +23,6 @@ // An operation queue for top alerts @property (nonnull, strong, nonatomic) NSOperationQueue *topAlertQueue; -/// Stores any page dependencies for top alerts -@property (nonnull, strong, nonatomic) NSOperationQueue *pageOperations; - /// Returns the shared instance of this singleton + (nullable instancetype)sharedAlertHandler; diff --git a/MVMCoreUI/Alerts/MVMCoreAlertHandler.m b/MVMCoreUI/Alerts/MVMCoreAlertHandler.m index 4e7be1f7..8b4b02c7 100644 --- a/MVMCoreUI/Alerts/MVMCoreAlertHandler.m +++ b/MVMCoreUI/Alerts/MVMCoreAlertHandler.m @@ -14,7 +14,7 @@ #import #import #import -#import +#import @interface MVMCoreAlertHandler () @@ -42,7 +42,7 @@ self.popupAlertQueue.maxConcurrentOperationCount = 1; self.topAlertQueue = [[NSOperationQueue alloc] init]; self.topAlertQueue.maxConcurrentOperationCount = 1; - self.pageOperations = [[NSOperationQueue alloc] init]; + [self registerForPageChanges]; } return self; } @@ -172,17 +172,11 @@ alertOperation = nil; }]; - [self.topAlertQueue addOperation:alertOperation]; + NSString *currentPageType = ((UIViewController *)[[MVMCoreUISplitViewController mainSplitViewController] getCurrentDetailViewController]).pageType; + [alertOperation updateDisplayableByPageType:currentPageType]; - // If the current running operation is persistent and has a lower queue priority then the added operation, cancel it and re-add it. - for (MVMCoreTopAlertOperation *operation in self.topAlertQueue.operations) { - - if (operation.isExecuting && !operation.isCancelled && operation.topAlertObject.persistent && operation.queuePriority < alertOperation.queuePriority && alertOperation.isReady) { - operation.reAddAfterCancel = YES; - [operation cancel]; - break; - } - } + [self.topAlertQueue addOperation:alertOperation]; + [self reevaluteQueue]; } - (void)showTopAlertWithObject:(nullable MVMCoreTopAlertObject *)topAlertObject { diff --git a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift index 4a40c728..ff262876 100644 --- a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift +++ b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift @@ -203,6 +203,7 @@ import Foundation MoleculeObjectMapping.shared()?.register(viewClass: ListFourColumnDataUsageListItem.self, viewModelClass: ListFourColumnDataUsageListItemModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ListProgressBarThin.self, viewModelClass: ListProgressBarThinModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ListStoreLocator.self, viewModelClass: ListStoreLocatorModel.self) + MoleculeObjectMapping.shared()?.register(viewClass: ListStarRating.self, viewModelClass: ListStarRatingModel.self) // MARK:- Designed Section Dividers MoleculeObjectMapping.shared()?.register(viewClass: ListFourColumnDataUsageDivider.self, viewModelClass: ListFourColumnDataUsageDividerModel.self) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Miscellaneous/ListStarRating.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Miscellaneous/ListStarRating.swift new file mode 100644 index 00000000..b4bcf03d --- /dev/null +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Miscellaneous/ListStarRating.swift @@ -0,0 +1,59 @@ +// +// ListStarRating.swift +// MVMCoreUI +// +// Created by Lekshmi S on 22/10/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +@objcMembers open class ListStarRating: TableViewCell { + //----------------------------------------------------- + // MARK: - Outlets + //----------------------------------------------------- + public let stars = Stars() + public var reviewsCount = Label(fontStyle: .RegularBodySmall) + public lazy var stack: Stack = { + return Stack.createStack(with: [(view: stars, model: StackItemModel(horizontalAlignment: .fill)), + (view: reviewsCount, model: StackItemModel(horizontalAlignment: .leading))], + axis: .horizontal, spacing: Padding.Two) + }() + + //----------------------------------------------------- + // MARK: - Lifecycle + //----------------------------------------------------- + override open func setupView() { + super.setupView() + addMolecule(stack) + stack.restack() + } + + //---------------------------------------------------- + // MARK: - Molecule + //---------------------------------------------------- + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + super.set(with: model, delegateObject, additionalData) + + guard let model = model as? ListStarRatingModel else { return } + stars.set(with: model.stars, delegateObject, additionalData) + reviewsCount.set(with: model.reviewsCount, delegateObject, additionalData) + updateAccessibilityLabel() + } + + open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { + return 90 + } + + // MARK: - Accessibility + func updateAccessibilityLabel() { + isAccessibilityElement = true + var message = "" + if let starsLabel = stars.accessibilityLabel { + message += starsLabel + ", " + } + + if let reviewsCountLabelText = reviewsCount.text, let reviewText = MVMCoreUIUtility.hardcodedString(withKey: "review_text") { + message += reviewsCountLabelText + reviewText + } + accessibilityLabel = message + } +} diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Miscellaneous/ListStarRatingModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Miscellaneous/ListStarRatingModel.swift new file mode 100644 index 00000000..6838f0b0 --- /dev/null +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Miscellaneous/ListStarRatingModel.swift @@ -0,0 +1,52 @@ +// +// ListStarRatingModel.swift +// MVMCoreUI +// +// Created by Lekshmi S on 22/10/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +open class ListStarRatingModel: ListItemModel, MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public static var identifier: String = "listStarRating" + public var stars: StarsModel + public var reviewsCount: LabelModel + + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + public init(stars: StarsModel, reviewsCount: LabelModel) { + self.stars = stars + self.reviewsCount = reviewsCount + super.init() + } + + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { + case moleculeName + case stars + case reviewsCount + } + + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + stars = try typeContainer.decode(StarsModel.self, forKey: .stars) + reviewsCount = try typeContainer.decode(LabelModel.self, forKey: .reviewsCount) + try super.init(from: decoder) + } + + open override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encode(stars, forKey: .stars) + try container.encode(reviewsCount, forKey: .reviewsCount) + } +} diff --git a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings index f14fe02e..ba70fc2b 100644 --- a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings @@ -92,3 +92,4 @@ "star" = "Star"; "star_percent" = "%d percent progress"; "stars_filled" = "%.1f out of %d stars"; +"review_text" = " reviews"; diff --git a/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings index 4d14292c..b279ccdb 100644 --- a/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings @@ -70,3 +70,4 @@ "star" = "Estrella"; "star_percent" = "%@ porcentaje de progreso"; "stars_filled" = "%.1f de %d estrellas"; +"review_text" = " críticas"; diff --git a/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings index 585e2c1a..0c441812 100644 --- a/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings @@ -75,3 +75,4 @@ "star" = "Estrella"; "star_percent" = "%@ porcentaje de progreso"; "stars_filled" = "%.1f de %d estrellas"; +"review_text" = " críticas"; diff --git a/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.h b/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.h index 73acec1e..af00d789 100644 --- a/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.h +++ b/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.h @@ -15,6 +15,9 @@ @property (readonly, getter=isPaused) BOOL paused; +/// A bool for if this top alert can be displayed. It is only ready if true. +@property (nonatomic, getter=isDisplayable) BOOL displayable; + @property (nonatomic) BOOL reAddAfterCancel; @property (nonnull, nonatomic, strong) MVMCoreTopAlertObject *topAlertObject; @@ -24,6 +27,9 @@ /// Updates the operation with a new object - (void)updateWithTopAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject; +/// Updates the operation isDisplayable based on the page type. +- (void)updateDisplayableByPageType:(nullable NSString *)pageType; + // Pauses the operation. Temporarily removes any alert. - (void)pause; diff --git a/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.m b/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.m index bcf9515a..7a57f989 100644 --- a/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.m +++ b/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.m @@ -10,11 +10,13 @@ #import "MVMCoreTopAlertObject.h" #import "MVMCoreAlertHandler.h" #import +#import @interface MVMCoreTopAlertOperation () { __block BOOL _paused; __block BOOL _displayed; __block BOOL _animating; + __block BOOL _displayable; } @property (readwrite, getter=isPaused) BOOL paused; @@ -25,6 +27,7 @@ @property (strong, nonatomic) dispatch_queue_t pausedQueue; @property (strong, nonatomic) dispatch_queue_t displayedQueue; @property (strong, nonatomic) dispatch_queue_t animatingQueue; +@property (strong, nonatomic) dispatch_queue_t displayableQueue; @property (nonatomic, strong) dispatch_source_t timerSource; @@ -39,6 +42,8 @@ self.pausedQueue = dispatch_queue_create("paused", DISPATCH_QUEUE_CONCURRENT); self.displayedQueue = dispatch_queue_create("displayed", DISPATCH_QUEUE_CONCURRENT); self.animatingQueue = dispatch_queue_create("animating", DISPATCH_QUEUE_CONCURRENT); + self.displayableQueue = dispatch_queue_create("displayable", DISPATCH_QUEUE_CONCURRENT); + self.displayable = YES; } return self; } @@ -66,6 +71,19 @@ } } +- (void)updateDisplayableByPageType:(nullable NSString *)pageType { + NSArray *pages = [self.topAlertObject.json array:@"pages"]; + if (pages.count == 0) { + self.displayable = YES; + return; + } + if (pageType.length == 0) { + self.displayable = NO; + return; + } + self.displayable = [pages containsObject:pageType]; +} + - (BOOL)isPaused { __block BOOL isPaused; dispatch_sync(self.pausedQueue, ^{ @@ -108,6 +126,37 @@ }); } + +- (BOOL)isDisplayable { + __block BOOL isDisplayable; + dispatch_sync(self.displayableQueue, ^{ + isDisplayable = self->_displayable; + }); + return isDisplayable; +} + +- (void)setDisplayable:(BOOL)displayable { + if (displayable != self.isDisplayable) { + BOOL isReady = [super isReady]; + if (isReady) { + [self willChangeValueForKey:@"isReady"]; + } + dispatch_barrier_async(self.displayableQueue, ^{ + self->_displayable = displayable; + }); + if (isReady) { + [self didChangeValueForKey:@"isReady"]; + } + } +} + +- (BOOL)isReady { + if (self.isCancelled) { + return [super isReady]; + } + return [super isReady] && self.isDisplayable; +} + - (void)main { // Always check for cancellation before launching the task. @@ -251,6 +300,7 @@ copyObject.topAlertObject = self.topAlertObject; copyObject.paused = self.paused; copyObject.reAddAfterCancel = self.reAddAfterCancel; + copyObject.displayable = self.isDisplayable; copyObject.queuePriority = self.queuePriority; for (NSOperation *dependency in self.dependencies) { [copyObject addDependency:dependency]; diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift index 9bceb57a..a0b128b2 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift @@ -18,7 +18,6 @@ public extension MVMCoreUITopAlertView { /// Registers with the notification center to know when json is updated. @objc func registerWithNotificationCenter() { NotificationCenter.default.addObserver(self, selector: #selector(responseJSONUpdated(notification:)), name: NSNotification.Name(rawValue: NotificationResponseLoaded), object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(viewControllerChanged(notification:)), name: NSNotification.Name(rawValue: MVMCoreNotificationViewControllerChanged), object: nil) } private func getDelegateObject() -> MVMCoreUIDelegateObject { @@ -42,42 +41,6 @@ public extension MVMCoreUITopAlertView { showTopAlert(with: model) } - /// When a detail page changes, check top alerts. - @objc private func viewControllerChanged(notification: Notification) { - guard let controller = MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() as? MVMCoreViewControllerProtocol else { return } - MVMCoreAlertHandler.shared()?.handleAllPagesDependency(for: controller.pageType) - reevalutePriority() - } - - /// Re-evaluates the queue priority - private func reevalutePriority() { - guard let operations = MVMCoreAlertHandler.shared()?.topAlertQueue.operations else { return } - var highestReadyOperation: Operation? - var executingOperation: Operation? - for operation in operations { - guard !operation.isCancelled, - !operation.isFinished else { - continue - } - if operation.isReady, - highestReadyOperation == nil || operation.queuePriority.rawValue > highestReadyOperation!.queuePriority.rawValue { - highestReadyOperation = operation - } - if operation.isExecuting { - executingOperation = operation - } - } - - // If the highest priority operation is not executing, and the executing operation is persistent, cancel it. - if let newOperation = highestReadyOperation, - let currentOperation = executingOperation as? MVMCoreTopAlertOperation, - currentOperation != newOperation, - currentOperation.topAlertObject.persistent { - currentOperation.reAddAfterCancel = true - currentOperation.cancel() - } - } - /// Decodes the json into a TopNotificationModel private func decodeTopNotification(with json: [AnyHashable: Any], delegateObject: MVMCoreUIDelegateObject?) -> TopNotificationModel? { do { @@ -95,8 +58,6 @@ public extension MVMCoreUITopAlertView { let object = model.createTopAlertObject() guard !checkAndUpdateExisting(with: object), let operation = MVMCoreTopAlertOperation(topAlertObject: object) else { return } - MVMCoreAlertHandler.shared()?.addPagesDependency(to: operation) - MVMCoreAlertHandler.shared()?.handlePageDependency(for: operation, with: (MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() as? MVMCoreViewControllerProtocol)?.pageType) MVMCoreAlertHandler.shared()?.add(operation) } @@ -107,9 +68,9 @@ public extension MVMCoreUITopAlertView { guard topAlertObject.json != nil, operation.topAlertObject.type == topAlertObject.type else { continue } operation.update(with: topAlertObject) - MVMCoreAlertHandler.shared()?.updatePages(for: operation, with: topAlertObject) - MVMCoreAlertHandler.shared()?.handlePageDependency(for: operation, with: (MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() as? MVMCoreViewControllerProtocol)?.pageType) - reevalutePriority() + let pageType = (MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() as? MVMCoreViewControllerProtocol)?.pageType + operation.updateDisplayable(byPageType: pageType) + MVMCoreAlertHandler.shared()?.reevaluteQueue() return true } return false