mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 06:35:51 +00:00
Make sure range controller listens to node display notifications if absolutely needed
This commit is contained in:
@@ -245,9 +245,9 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
dispatch_once(&onceToken, ^{
|
||||
renderQueue = [[ASRunLoopQueue<ASDisplayNode *> alloc] initWithRunLoop:CFRunLoopGetMain()
|
||||
andHandler:^(ASDisplayNode * _Nonnull dequeuedItem, BOOL isQueueDrained) {
|
||||
CFAbsoluteTime timestamp = isQueueDrained ? CFAbsoluteTimeGetCurrent() : 0;
|
||||
[dequeuedItem _recursivelyTriggerDisplayAndBlock:NO];
|
||||
if (isQueueDrained) {
|
||||
CFAbsoluteTime timestamp = CFAbsoluteTimeGetCurrent();
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ASRenderingEngineDidDisplayScheduledNodesNotification
|
||||
object:nil
|
||||
userInfo:@{ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp: @(timestamp)}];
|
||||
@@ -2317,25 +2317,25 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
||||
});
|
||||
}
|
||||
|
||||
- (void)recursivelySetInterfaceState:(ASInterfaceState)interfaceState
|
||||
- (void)recursivelySetInterfaceState:(ASInterfaceState)newInterfaceState
|
||||
{
|
||||
ASInterfaceState oldState = self.interfaceState;
|
||||
ASInterfaceState newState = interfaceState;
|
||||
ASDisplayNodePerformBlockOnEveryNode(nil, self, ^(ASDisplayNode *node) {
|
||||
node.interfaceState = interfaceState;
|
||||
});
|
||||
|
||||
if ([self supportsRangeManagedInterfaceState]) {
|
||||
// Instead of each node in the recursion assuming it needs to schedule itself for display,
|
||||
// setInterfaceState: skips this when handling range-managed nodes (our whole subtree has this set).
|
||||
// If our range manager intends for us to be displayed right now, and didn't before, get started!
|
||||
|
||||
BOOL nowDisplay = ASInterfaceStateIncludesDisplay(newState);
|
||||
BOOL wasDisplay = ASInterfaceStateIncludesDisplay(oldState);
|
||||
if (nowDisplay && (nowDisplay != wasDisplay)) {
|
||||
BOOL shouldScheduleDisplay = [self supportsRangeManagedInterfaceState] && [self shouldScheduleDisplayWithNewInterfaceState:newInterfaceState];
|
||||
ASDisplayNodePerformBlockOnEveryNode(nil, self, ^(ASDisplayNode *node) {
|
||||
node.interfaceState = newInterfaceState;
|
||||
});
|
||||
if (shouldScheduleDisplay) {
|
||||
[ASDisplayNode scheduleNodeForRecursiveDisplay:self];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)shouldScheduleDisplayWithNewInterfaceState:(ASInterfaceState)newInterfaceState
|
||||
{
|
||||
BOOL willDisplay = ASInterfaceStateIncludesDisplay(newInterfaceState);
|
||||
BOOL nowDisplay = ASInterfaceStateIncludesDisplay(self.interfaceState);
|
||||
return willDisplay && (willDisplay != nowDisplay);
|
||||
}
|
||||
|
||||
- (ASHierarchyState)hierarchyState
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
NSSet<NSIndexPath *> *_allPreviousIndexPaths;
|
||||
ASLayoutRangeMode _currentRangeMode;
|
||||
BOOL _didUpdateCurrentRange;
|
||||
BOOL _didRegisterForNotifications;
|
||||
BOOL _didRegisterForNodeDisplayNotifications;
|
||||
CFAbsoluteTime _pendingDisplayNodesTimestamp;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (_didRegisterForNotifications) {
|
||||
if (_didRegisterForNodeDisplayNotifications) {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:ASRenderingEngineDidDisplayScheduledNodesNotification object:nil];
|
||||
}
|
||||
}
|
||||
@@ -242,10 +242,6 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive;
|
||||
[allIndexPaths addObjectsFromArray:ASIndexPathsForTwoDimensionalArray(allNodes)];
|
||||
}
|
||||
|
||||
// TODO Don't register for notifications if this range update doesn't cause any node to enter rendering pipeline.
|
||||
// This can be done once there is an API to observe to (or be notified upon) interface state changes or pipeline enterings
|
||||
[self registerForNotificationsForInterfaceStateIfNeeded:selfInterfaceState];
|
||||
|
||||
#if ASRangeControllerLoggingEnabled
|
||||
ASDisplayNodeAssertTrue([visibleIndexPaths isSubsetOfSet:displayIndexPaths]);
|
||||
NSMutableArray<NSIndexPath *> *modifiedIndexPaths = (ASRangeControllerLoggingEnabled ? [NSMutableArray array] : nil);
|
||||
@@ -309,15 +305,20 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive;
|
||||
#if ASRangeControllerLoggingEnabled
|
||||
[modifiedIndexPaths addObject:indexPath];
|
||||
#endif
|
||||
[node recursivelySetInterfaceState:interfaceState];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_didRegisterForNotifications) {
|
||||
BOOL nodeShouldScheduleDisplay = [node shouldScheduleDisplayWithNewInterfaceState:interfaceState];
|
||||
[node recursivelySetInterfaceState:interfaceState];
|
||||
|
||||
if (nodeShouldScheduleDisplay) {
|
||||
[self registerForNodeDisplayNotificationsForInterfaceStateIfNeeded:selfInterfaceState];
|
||||
if (_didRegisterForNodeDisplayNotifications) {
|
||||
_pendingDisplayNodesTimestamp = CFAbsoluteTimeGetCurrent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_rangeIsValid = YES;
|
||||
_queuedRangeUpdate = NO;
|
||||
@@ -338,9 +339,9 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive;
|
||||
|
||||
#pragma mark - Notification observers
|
||||
|
||||
- (void)registerForNotificationsForInterfaceStateIfNeeded:(ASInterfaceState)interfaceState
|
||||
- (void)registerForNodeDisplayNotificationsForInterfaceStateIfNeeded:(ASInterfaceState)interfaceState
|
||||
{
|
||||
if (!_didRegisterForNotifications) {
|
||||
if (!_didRegisterForNodeDisplayNotifications) {
|
||||
ASLayoutRangeMode nextRangeMode = [ASRangeController rangeModeForInterfaceState:interfaceState
|
||||
currentRangeMode:_currentRangeMode];
|
||||
if (_currentRangeMode != nextRangeMode) {
|
||||
@@ -348,7 +349,7 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive;
|
||||
selector:@selector(scheduledNodesDidDisplay:)
|
||||
name:ASRenderingEngineDidDisplayScheduledNodesNotification
|
||||
object:nil];
|
||||
_didRegisterForNotifications = YES;
|
||||
_didRegisterForNodeDisplayNotifications = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -359,7 +360,7 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive;
|
||||
if (_pendingDisplayNodesTimestamp < notificationTimestamp) {
|
||||
// The rendering engine has processed all the nodes this range controller scheduled. Let's schedule a range update
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:ASRenderingEngineDidDisplayScheduledNodesNotification object:nil];
|
||||
_didRegisterForNotifications = NO;
|
||||
_didRegisterForNodeDisplayNotifications = NO;
|
||||
|
||||
[self scheduleRangeUpdate];
|
||||
}
|
||||
|
||||
@@ -135,6 +135,11 @@ inline BOOL ASHierarchyStateIncludesRangeManaged(ASHierarchyState hierarchyState
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL shouldBypassEnsureDisplay;
|
||||
|
||||
/**
|
||||
* @abstract Checks whether a node should be scheduled for display, considering its current and new interface states.
|
||||
*/
|
||||
- (BOOL)shouldScheduleDisplayWithNewInterfaceState:(ASInterfaceState)newInterfaceState;
|
||||
|
||||
@end
|
||||
|
||||
@interface UIView (ASDisplayNodeInternal)
|
||||
|
||||
Reference in New Issue
Block a user