diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift index 6a3c78de..58a06420 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift @@ -21,13 +21,13 @@ public extension MVMCoreUITopAlertView { NotificationCenter.default.addObserver(self, selector: #selector(viewControllerChanged(notification:)), name: NSNotification.Name(rawValue: MVMCoreNotificationViewControllerChanged), object: nil) } - @objc func getDelegateObject() -> MVMCoreUIDelegateObject { + private func getDelegateObject() -> MVMCoreUIDelegateObject { // TODO: Top alert view is current delegate. Should move to current view controller eventually? return MVMCoreUIDelegateObject.create(withDelegateForAll: self) } /// Checks for new top alert json - @objc func responseJSONUpdated(notification: Notification) { + @objc private func responseJSONUpdated(notification: Notification) { guard let responseJSON = (notification.userInfo?[String(describing: MVMCoreLoadObject.self)] as? MVMCoreLoadObject)?.responseJSON, let json = responseJSON.optionalDictionaryForKey("TopNotification"), let model = decodeTopNotification(with: json, delegateObject: getDelegateObject()) else { return } @@ -35,13 +35,43 @@ public extension MVMCoreUITopAlertView { } /// When a detail page changes, check top alerts. - @objc func viewControllerChanged(notification: Notification) { + @objc private func viewControllerChanged(notification: Notification) { guard let controller = MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() as? MVMCoreViewControllerProtocol else { return } - MVMCoreAlertHandler.shared()?.checkPagesDependency(for: controller.pageType) + 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 - func decodeTopNotification(with json: [AnyHashable: Any], delegateObject: MVMCoreUIDelegateObject?) -> TopNotificationModel? { + private func decodeTopNotification(with json: [AnyHashable: Any], delegateObject: MVMCoreUIDelegateObject?) -> TopNotificationModel? { do { return try TopNotificationModel.decode(json: json, delegateObject: delegateObject) } catch { @@ -55,7 +85,26 @@ public extension MVMCoreUITopAlertView { /// Shows the top alert with the model. func showTopAlert(with model: TopNotificationModel) { let object = model.createTopAlertObject() - MVMCoreAlertHandler.shared()?.showTopAlert(with: object) + 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) + } + + /// Checks for existing top alert object of same type and updates it. Only happens for molecular top alerts. Returns true if we updated. + private func checkAndUpdateExisting(with topAlertObject: MVMCoreTopAlertObject) -> Bool { + guard let queue = MVMCoreAlertHandler.shared()?.topAlertQueue.operations else { return false } + for case let operation as MVMCoreTopAlertOperation in queue { + 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() + return true + } + return false } /// Updates the current top alert molecule with the new object