diff --git a/MVMCore/MVMCore.xcodeproj/project.pbxproj b/MVMCore/MVMCore.xcodeproj/project.pbxproj index a0778b2..12ade7f 100644 --- a/MVMCore/MVMCore.xcodeproj/project.pbxproj +++ b/MVMCore/MVMCore.xcodeproj/project.pbxproj @@ -597,9 +597,9 @@ AFBB967D1FBA3A9A0008D868 /* MVMCoreAlertDelegateProtocol.h */, AFBB967E1FBA3A9A0008D868 /* MVMCoreAlertHandler.h */, AFBB967F1FBA3A9A0008D868 /* MVMCoreAlertHandler.m */, + D2CAC7C72510F0C500C75681 /* MVMCoreAlertHandler+Extension.swift */, AFBB96801FBA3A9A0008D868 /* MVMCoreAlertObject.h */, AFBB96811FBA3A9A0008D868 /* MVMCoreAlertObject.m */, - D2CAC7C72510F0C500C75681 /* MVMCoreAlertHandler+Extension.swift */, 0184D3E224B8D0C600A05369 /* MVMCoreAlertObject+Swift.swift */, AFBB96821FBA3A9A0008D868 /* MVMCoreAlertOperation.h */, AFBB96831FBA3A9A0008D868 /* MVMCoreAlertOperation.m */, diff --git a/MVMCore/MVMCore/AlertHandling/MVMCoreAlertHandler+Extension.swift b/MVMCore/MVMCore/AlertHandling/MVMCoreAlertHandler+Extension.swift index ff79aa7..9ee8ff9 100644 --- a/MVMCore/MVMCore/AlertHandling/MVMCoreAlertHandler+Extension.swift +++ b/MVMCore/MVMCore/AlertHandling/MVMCoreAlertHandler+Extension.swift @@ -63,4 +63,16 @@ public extension MVMCoreAlertHandler { } } } + + /// Checks for existing top alert object of same type and updates it. Only happens for molecular top alerts. Returns true if we updated. + @objc func checkAndUpdateExisting(with topAlertObject: MVMCoreTopAlertObject) -> Bool { + // ToDo: do pages and priority. + for case let operation as MVMCoreTopAlertOperation in topAlertQueue.operations { + guard topAlertObject.json != nil, + operation.topAlertObject.type == topAlertObject.type else { continue } + operation.update(with: topAlertObject) + return true + } + return false + } } diff --git a/MVMCore/MVMCore/AlertHandling/MVMCoreAlertHandler.m b/MVMCore/MVMCore/AlertHandling/MVMCoreAlertHandler.m index 1e64663..1dab33b 100644 --- a/MVMCore/MVMCore/AlertHandling/MVMCoreAlertHandler.m +++ b/MVMCore/MVMCore/AlertHandling/MVMCoreAlertHandler.m @@ -160,7 +160,8 @@ - (void)showTopAlertWithObject:(nullable MVMCoreTopAlertObject *)topAlertObject { - if (topAlertObject) { + // Check if we need to add a new operation. + if (topAlertObject && ![self checkAndUpdateExistingWith:topAlertObject]) { __block MVMCoreTopAlertOperation *alertOperation = [[MVMCoreTopAlertOperation alloc] initWithTopAlertObject:topAlertObject]; __weak typeof(self) weakSelf = self; diff --git a/MVMCore/MVMCore/AlertHandling/MVMCoreTopAlertOperation.h b/MVMCore/MVMCore/AlertHandling/MVMCoreTopAlertOperation.h index 82cba7d..6dadc89 100644 --- a/MVMCore/MVMCore/AlertHandling/MVMCoreTopAlertOperation.h +++ b/MVMCore/MVMCore/AlertHandling/MVMCoreTopAlertOperation.h @@ -21,6 +21,9 @@ - (nullable instancetype)initWithTopAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject; +/// Updates the operation with a new object +- (void)updateWithTopAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject; + // Pauses the operation. Temporarily removes any alert. - (void)pause; diff --git a/MVMCore/MVMCore/AlertHandling/MVMCoreTopAlertOperation.m b/MVMCore/MVMCore/AlertHandling/MVMCoreTopAlertOperation.m index ccf7545..bab7707 100644 --- a/MVMCore/MVMCore/AlertHandling/MVMCoreTopAlertOperation.m +++ b/MVMCore/MVMCore/AlertHandling/MVMCoreTopAlertOperation.m @@ -27,6 +27,8 @@ @property (strong, nonatomic) dispatch_queue_t displayedQueue; @property (strong, nonatomic) dispatch_queue_t animatingQueue; +@property (nonatomic, strong) dispatch_source_t timerSource; + @end @implementation MVMCoreTopAlertOperation @@ -53,6 +55,18 @@ return self; } +- (void)updateWithTopAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject { + self.topAlertObject = topAlertObject; + self.queuePriority = [[MVMCoreObject sharedInstance].globalTopAlertDelegate priorityForTopAlertByObject:topAlertObject]; + if (self.isExecuting && !self.isCancelled && !self.isPaused) { + [self updateDismissTimer]; + UIView *topAlertView = [[MVMCoreObject sharedInstance].globalTopAlertDelegate getTopAlertView]; + if ([topAlertView respondsToSelector:@selector(updateTopAlertWith:)]) { + [topAlertView updateTopAlertWith:topAlertObject]; + } + } +} + - (BOOL)isPaused { __block BOOL isPaused; dispatch_sync(self.pausedQueue, ^{ @@ -126,23 +140,8 @@ // Paused, dismiss for the time being if persistent. [self dismissAlertView:!self.topAlertObject.persistent forceful:YES]; - } else if (!self.topAlertObject.persistent) { - - // Set timer to dismiss top alert if it's not persistent (or it's survival mode and not short bar). - NSInteger dismissTime; - if (self.topAlertObject.topAlertDismissTime > 0) { - dismissTime = self.topAlertObject.topAlertDismissTime; - } else { - dismissTime = TopAlertDismissTime; - } - - __weak typeof(self) weakSelf = self; - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(dismissTime * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - if (weakSelf.isFinished || [weakSelf checkAndHandleForCancellation]) { - return; - } - [weakSelf dismissAlertView:YES forceful:NO]; - }); + } else { + [self updateDismissTimer]; } }]; } @@ -152,6 +151,35 @@ } } +/// Updates the timer to dismiss the top alert. +- (void)updateDismissTimer { + if (self.timerSource) { + dispatch_source_cancel(self.timerSource); + } + if (self.topAlertObject.persistent) { + return; + } + + NSInteger dismissTime; + if (self.topAlertObject.topAlertDismissTime > 0) { + dismissTime = self.topAlertObject.topAlertDismissTime; + } else { + dismissTime = TopAlertDismissTime; + } + + self.timerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue()); + dispatch_source_set_timer(self.timerSource, dispatch_time(DISPATCH_TIME_NOW, dismissTime * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, (1ull * NSEC_PER_SEC) / 10); + + __weak typeof(self) weakSelf = self; + dispatch_source_set_event_handler(self.timerSource, ^{ + if (weakSelf.isFinished || [weakSelf checkAndHandleForCancellation]) { + return; + } + [weakSelf dismissAlertView:YES forceful:NO]; + }); + dispatch_resume(self.timerSource); +} + - (void)cancel { [super cancel]; @@ -167,7 +195,9 @@ } - (void)dismissAlertView:(BOOL)andFinish forceful:(BOOL)forceful { - + if (self.timerSource) { + dispatch_source_cancel(self.timerSource); + } if (self.isDisplayed && !self.isAnimating) { // Dismisses. diff --git a/MVMCore/MVMCore/AlertHandling/MVMCoreTopAlertViewProtocol.h b/MVMCore/MVMCore/AlertHandling/MVMCoreTopAlertViewProtocol.h index f667037..2778971 100644 --- a/MVMCore/MVMCore/AlertHandling/MVMCoreTopAlertViewProtocol.h +++ b/MVMCore/MVMCore/AlertHandling/MVMCoreTopAlertViewProtocol.h @@ -22,4 +22,7 @@ // Collapses the notification if it has a short top message. Otherwise removes notification. - (void)collapseNotification; +/// Updates the existing top alert with the new object +- (void)updateTopAlertWith:(nullable MVMCoreTopAlertObject *)topAlertObject; + @end