1
0
mirror of https://github.com/danog/Telegram.git synced 2024-12-04 02:17:51 +01:00
Telegram/Watch/Extension/TGTableDeltaUpdater.m
2015-10-01 19:19:52 +03:00

177 lines
4.7 KiB
Objective-C

#import "TGTableDeltaUpdater.h"
#import "WKInterfaceTable+TGDataDrivenTable.h"
@implementation TGTableAlignment
+ (instancetype)insertionWithPos:(NSInteger)pos len:(NSInteger)len
{
TGTableAlignment *alignment = [[TGTableAlignment alloc] init];
alignment.pos = pos;
alignment.len = len;
return alignment;
}
+ (instancetype)deletionWithPos:(NSInteger)pos len:(NSInteger)len
{
TGTableAlignment *alignment = [[TGTableAlignment alloc] init];
alignment.deletion = true;
alignment.pos = pos;
alignment.len = len;
return alignment;
}
@end
@implementation TGTableDeltaUpdater
+ (NSArray *)longestCommonSubsequenceForOldData:(NSArray *)oldData newData:(NSArray *)newData
{
NSUInteger x = oldData.count;
NSUInteger y = newData.count;
NSInteger lens[x + 1][y + 1];
for (NSUInteger i = 0; i < (x + 1); i++)
{
for (NSUInteger j = 0; j < (y + 1); j++)
{
lens[i][j] = 0;
}
}
NSMutableArray *result = [[NSMutableArray alloc] init];
for (NSUInteger i = 0; i < x; i++)
{
for (NSUInteger j = 0; j < y; j++)
{
NSObject<TGTableItem> *oldItem = oldData[i];
NSObject<TGTableItem> *newItem = newData[j];
if ([[oldItem uniqueIdentifier] isEqual:[newItem uniqueIdentifier]])
lens[i + 1][j + 1] = lens[i][j] + 1;
else
lens[i + 1][j + 1] = MAX(lens[i + 1][j], lens[i][j + 1]);
}
}
while (x != 0 && y != 0)
{
if (lens[x][y] == lens[x - 1][y])
{
--x;
}
else if (lens[x][y] == lens[x][y - 1])
{
--y;
}
else
{
[result insertObject:oldData[x - 1] atIndex:0];
--x;
--y;
}
}
return result;
}
+ (NSArray *)differenceForOldData:(NSArray *)left newData:(NSArray *)right
{
NSArray *lcs = [self longestCommonSubsequenceForOldData:left newData:right];
NSInteger left_i = 0;
NSInteger right_i = 0;
NSInteger totalOffset = 0;
NSMutableArray *changes = [[NSMutableArray alloc] init];
for (NSObject<TGTableItem> *element in lcs)
{
NSInteger leftOffset = 0;
NSInteger rightOffset = 0;
while (true)
{
if ([[left[left_i] uniqueIdentifier] isEqual:[element uniqueIdentifier]])
{
break;
}
else
{
left_i++;
leftOffset++;
}
}
while (true)
{
if ([[right[right_i] uniqueIdentifier] isEqual:[element uniqueIdentifier]])
{
break;
}
else
{
right_i++;
rightOffset++;
}
}
if (rightOffset > leftOffset)
{
NSInteger insertions = rightOffset - leftOffset;
NSInteger pos = left_i + totalOffset;
[changes addObject:[TGTableAlignment insertionWithPos:pos len:insertions]];
totalOffset += insertions;
}
else if (leftOffset > rightOffset)
{
NSInteger deletions = leftOffset - rightOffset;
NSInteger pos = left_i - deletions + totalOffset;
[changes addObject:[TGTableAlignment deletionWithPos:pos len:deletions]];
totalOffset -= deletions;
}
left_i++;
right_i++;
}
NSInteger afterLastInLeft = left.count - left_i;
NSInteger afterLastInRight = right.count - right_i;
if (afterLastInRight > afterLastInLeft)
{
NSInteger insertions = afterLastInRight - afterLastInLeft;
NSInteger pos = left_i + totalOffset;
[changes addObject:[TGTableAlignment insertionWithPos:pos len:insertions]];
}
else if (afterLastInLeft > afterLastInRight)
{
NSInteger deletions = afterLastInLeft - afterLastInRight;
NSInteger pos = left_i + totalOffset;
[changes addObject:[TGTableAlignment deletionWithPos:pos len:deletions]];
}
return changes;
}
+ (void)updateTable:(WKInterfaceTable *)table oldData:(NSArray *)oldData newData:(NSArray *)newData controllerClassForIndexPath:(Class (^)(TGIndexPath *indexPath))controllerClassForIndexPath
{
if (table.numberOfRows == 0)
{
[table reloadData];
return;
}
NSArray *changes = [self differenceForOldData:oldData newData:newData];
[table applyBatchChanges:changes];
NSMutableArray *reloads = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < newData.count; i++)
[reloads addObject:[TGIndexPath indexPathForRow:i inSection:0]];
[table reloadRowsAtIndexPaths:reloads];
}
@end