mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Improving handling of edge cases in conversation view.
This commit is contained in:
parent
658746093d
commit
6d4a05bbea
8 changed files with 438 additions and 333 deletions
|
@ -62,12 +62,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
- (CGFloat)audioDurationSeconds
|
- (CGFloat)audioDurationSeconds
|
||||||
{
|
{
|
||||||
NSNumber *_Nullable audioDurationSeconds = self.viewItem.audioDurationSeconds;
|
OWSAssert(self.viewItem.audioDurationSeconds);
|
||||||
if (!audioDurationSeconds) {
|
|
||||||
audioDurationSeconds = @([self.attachmentStream audioDurationSecondsWithoutTransaction]);
|
return [self.viewItem.audioDurationSeconds floatValue];
|
||||||
self.viewItem.audioDurationSeconds = audioDurationSeconds;
|
|
||||||
}
|
|
||||||
return [audioDurationSeconds floatValue];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (AudioPlaybackState)audioPlaybackState
|
- (AudioPlaybackState)audioPlaybackState
|
||||||
|
|
|
@ -97,7 +97,7 @@ static const int kYapDatabasePageSize = 50;
|
||||||
static const int kYapDatabaseMaxPageCount = 500;
|
static const int kYapDatabaseMaxPageCount = 500;
|
||||||
// Never show more than 6*50 = 300 messages in conversation view when user
|
// Never show more than 6*50 = 300 messages in conversation view when user
|
||||||
// arrives.
|
// arrives.
|
||||||
static const int kYapDatabaseMaxInitialPageCount = 6;
|
static const int kYapDatabaseMaxInitialPageCount = 500;
|
||||||
static const int kConversationInitialMaxRangeSize = kYapDatabasePageSize * kYapDatabaseMaxInitialPageCount;
|
static const int kConversationInitialMaxRangeSize = kYapDatabasePageSize * kYapDatabaseMaxInitialPageCount;
|
||||||
static const int kYapDatabaseRangeMaxLength = kYapDatabasePageSize * kYapDatabaseMaxPageCount;
|
static const int kYapDatabaseRangeMaxLength = kYapDatabasePageSize * kYapDatabaseMaxPageCount;
|
||||||
static const int kYapDatabaseRangeMinLength = 0;
|
static const int kYapDatabaseRangeMinLength = 0;
|
||||||
|
@ -2883,8 +2883,6 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
|
||||||
// b) is inserting new interactions.
|
// b) is inserting new interactions.
|
||||||
__block BOOL scrollToBottom = wasAtBottom;
|
__block BOOL scrollToBottom = wasAtBottom;
|
||||||
|
|
||||||
BOOL shouldAnimateUpdates = [self shouldAnimateRowUpdates:rowChanges oldViewItemCount:oldViewItemCount];
|
|
||||||
|
|
||||||
void (^batchUpdates)(void) = ^{
|
void (^batchUpdates)(void) = ^{
|
||||||
for (YapDatabaseViewRowChange *rowChange in rowChanges) {
|
for (YapDatabaseViewRowChange *rowChange in rowChanges) {
|
||||||
switch (rowChange.type) {
|
switch (rowChange.type) {
|
||||||
|
@ -2893,6 +2891,7 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
|
||||||
rowChange.collectionKey,
|
rowChange.collectionKey,
|
||||||
rowChange.indexPath,
|
rowChange.indexPath,
|
||||||
rowChange.finalIndex);
|
rowChange.finalIndex);
|
||||||
|
[DDLog flushLog];
|
||||||
[self.collectionView deleteItemsAtIndexPaths:@[ rowChange.indexPath ]];
|
[self.collectionView deleteItemsAtIndexPaths:@[ rowChange.indexPath ]];
|
||||||
YapCollectionKey *collectionKey = rowChange.collectionKey;
|
YapCollectionKey *collectionKey = rowChange.collectionKey;
|
||||||
OWSAssert(collectionKey.key.length > 0);
|
OWSAssert(collectionKey.key.length > 0);
|
||||||
|
@ -2903,6 +2902,7 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
|
||||||
rowChange.collectionKey,
|
rowChange.collectionKey,
|
||||||
rowChange.newIndexPath,
|
rowChange.newIndexPath,
|
||||||
rowChange.finalIndex);
|
rowChange.finalIndex);
|
||||||
|
[DDLog flushLog];
|
||||||
[self.collectionView insertItemsAtIndexPaths:@[ rowChange.newIndexPath ]];
|
[self.collectionView insertItemsAtIndexPaths:@[ rowChange.newIndexPath ]];
|
||||||
// We don't want to reload a row that we just inserted.
|
// We don't want to reload a row that we just inserted.
|
||||||
[rowsThatChangedSize removeObject:@(rowChange.finalIndex)];
|
[rowsThatChangedSize removeObject:@(rowChange.finalIndex)];
|
||||||
|
@ -2923,8 +2923,8 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
|
||||||
rowChange.indexPath,
|
rowChange.indexPath,
|
||||||
rowChange.newIndexPath,
|
rowChange.newIndexPath,
|
||||||
rowChange.finalIndex);
|
rowChange.finalIndex);
|
||||||
[self.collectionView deleteItemsAtIndexPaths:@[ rowChange.indexPath ]];
|
[DDLog flushLog];
|
||||||
[self.collectionView insertItemsAtIndexPaths:@[ rowChange.newIndexPath ]];
|
[self.collectionView moveItemAtIndexPath:rowChange.indexPath toIndexPath:rowChange.newIndexPath];
|
||||||
// We don't want to reload a row that we just moved.
|
// We don't want to reload a row that we just moved.
|
||||||
[rowsThatChangedSize removeObject:@(rowChange.finalIndex)];
|
[rowsThatChangedSize removeObject:@(rowChange.finalIndex)];
|
||||||
break;
|
break;
|
||||||
|
@ -2934,6 +2934,7 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
|
||||||
rowChange.collectionKey,
|
rowChange.collectionKey,
|
||||||
rowChange.indexPath,
|
rowChange.indexPath,
|
||||||
rowChange.finalIndex);
|
rowChange.finalIndex);
|
||||||
|
[DDLog flushLog];
|
||||||
[self.collectionView reloadItemsAtIndexPaths:@[ rowChange.indexPath ]];
|
[self.collectionView reloadItemsAtIndexPaths:@[ rowChange.indexPath ]];
|
||||||
// We don't want to reload a row that we've already reloaded.
|
// We don't want to reload a row that we've already reloaded.
|
||||||
[rowsThatChangedSize removeObject:@(rowChange.finalIndex)];
|
[rowsThatChangedSize removeObject:@(rowChange.finalIndex)];
|
||||||
|
@ -2946,40 +2947,151 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
|
||||||
// as they may affect which cells show "date" headers or "status" footers.
|
// as they may affect which cells show "date" headers or "status" footers.
|
||||||
NSMutableArray<NSIndexPath *> *rowsToReload = [NSMutableArray new];
|
NSMutableArray<NSIndexPath *> *rowsToReload = [NSMutableArray new];
|
||||||
for (NSNumber *row in rowsThatChangedSize) {
|
for (NSNumber *row in rowsThatChangedSize) {
|
||||||
|
DDLogVerbose(@"rowsToReload: %@", row);
|
||||||
[rowsToReload addObject:[NSIndexPath indexPathForRow:row.integerValue inSection:0]];
|
[rowsToReload addObject:[NSIndexPath indexPathForRow:row.integerValue inSection:0]];
|
||||||
}
|
}
|
||||||
if (rowsToReload.count > 0) {
|
if (rowsToReload.count > 0) {
|
||||||
|
[DDLog flushLog];
|
||||||
[self.collectionView reloadItemsAtIndexPaths:rowsToReload];
|
[self.collectionView reloadItemsAtIndexPaths:rowsToReload];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
void (^batchUpdatesCompletion)(BOOL) = ^(BOOL finished) {
|
|
||||||
OWSAssert([NSThread isMainThread]);
|
|
||||||
|
|
||||||
if (!finished) {
|
DDLogVerbose(@"self.viewItems.count: %zd -> %zd", oldViewItemCount, self.viewItems.count);
|
||||||
DDLogInfo(@"%@ performBatchUpdates did not finish", self.logTag);
|
[DDLog flushLog];
|
||||||
}
|
|
||||||
|
|
||||||
[self updateLastVisibleTimestamp];
|
BOOL shouldReloadCollection = [self shouldReloadCollection:rowChanges];
|
||||||
|
if (shouldReloadCollection) {
|
||||||
if (scrollToBottom) {
|
|
||||||
[self scrollToBottomAnimated:shouldAnimateScrollToBottom && shouldAnimateUpdates];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (shouldAnimateUpdates) {
|
|
||||||
[self.collectionView performBatchUpdates:batchUpdates completion:batchUpdatesCompletion];
|
|
||||||
} else {
|
|
||||||
[UIView performWithoutAnimation:^{
|
[UIView performWithoutAnimation:^{
|
||||||
[self.collectionView performBatchUpdates:batchUpdates completion:batchUpdatesCompletion];
|
[self.collectionView reloadData];
|
||||||
}];
|
}];
|
||||||
|
[self updateLastVisibleTimestamp];
|
||||||
|
} else {
|
||||||
|
BOOL shouldAnimateUpdates = [self shouldAnimateRowUpdates:rowChanges oldViewItemCount:oldViewItemCount];
|
||||||
|
void (^batchUpdatesCompletion)(BOOL) = ^(BOOL finished) {
|
||||||
|
OWSAssert([NSThread isMainThread]);
|
||||||
|
|
||||||
|
if (!finished) {
|
||||||
|
DDLogInfo(@"%@ performBatchUpdates did not finish", self.logTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
[self updateLastVisibleTimestamp];
|
||||||
|
|
||||||
|
if (scrollToBottom) {
|
||||||
|
[self scrollToBottomAnimated:shouldAnimateScrollToBottom && shouldAnimateUpdates];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (shouldAnimateUpdates) {
|
||||||
|
[self.collectionView performBatchUpdates:batchUpdates completion:batchUpdatesCompletion];
|
||||||
|
} else {
|
||||||
|
[UIView performWithoutAnimation:^{
|
||||||
|
[self.collectionView performBatchUpdates:batchUpdates completion:batchUpdatesCompletion];
|
||||||
|
}];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)shouldReloadCollection:(NSArray<YapDatabaseViewRowChange *> *)rowChanges
|
||||||
|
{
|
||||||
|
OWSAssert(rowChanges);
|
||||||
|
|
||||||
|
BOOL hasDeletes = NO;
|
||||||
|
BOOL hasInserts = NO;
|
||||||
|
BOOL hasMoves = NO;
|
||||||
|
BOOL hasUpdates = NO;
|
||||||
|
for (YapDatabaseViewRowChange *rowChange in rowChanges) {
|
||||||
|
switch (rowChange.type) {
|
||||||
|
case YapDatabaseViewChangeDelete:
|
||||||
|
DDLogVerbose(@"? YapDatabaseViewChangeDelete: %@, %@, %zd",
|
||||||
|
rowChange.collectionKey,
|
||||||
|
rowChange.indexPath,
|
||||||
|
rowChange.finalIndex);
|
||||||
|
[DDLog flushLog];
|
||||||
|
hasDeletes = YES;
|
||||||
|
break;
|
||||||
|
case YapDatabaseViewChangeInsert:
|
||||||
|
DDLogVerbose(@"...YapDatabaseViewChangeInsert: %@, %@, %zd",
|
||||||
|
rowChange.collectionKey,
|
||||||
|
rowChange.newIndexPath,
|
||||||
|
rowChange.finalIndex);
|
||||||
|
[DDLog flushLog];
|
||||||
|
hasInserts = YES;
|
||||||
|
break;
|
||||||
|
case YapDatabaseViewChangeMove:
|
||||||
|
DDLogVerbose(@"...YapDatabaseViewChangeMove: %@, %@, %@, %zd",
|
||||||
|
rowChange.collectionKey,
|
||||||
|
rowChange.indexPath,
|
||||||
|
rowChange.newIndexPath,
|
||||||
|
rowChange.finalIndex);
|
||||||
|
[DDLog flushLog];
|
||||||
|
hasMoves = YES;
|
||||||
|
break;
|
||||||
|
case YapDatabaseViewChangeUpdate:
|
||||||
|
DDLogVerbose(@"...YapDatabaseViewChangeUpdate: %@, %@, %zd",
|
||||||
|
rowChange.collectionKey,
|
||||||
|
rowChange.indexPath,
|
||||||
|
rowChange.finalIndex);
|
||||||
|
[DDLog flushLog];
|
||||||
|
hasUpdates = YES;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasMoves) {
|
||||||
|
// "Move" changes cannot be safely performed using
|
||||||
|
// [UICollectionView performBatchUpdates:]. This appears to be a
|
||||||
|
// bug in YapDatabase.
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
// if (hasDeletes && hasInserts) {
|
||||||
|
// return YES;
|
||||||
|
// }
|
||||||
|
// if (hasDeletes && hasUpdates) {
|
||||||
|
// return YES;
|
||||||
|
// }
|
||||||
|
// if (hasInserts && hasUpdates) {
|
||||||
|
// return YES;
|
||||||
|
// }
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)shouldAnimateRowUpdates:(NSArray<YapDatabaseViewRowChange *> *)rowChanges
|
- (BOOL)shouldAnimateRowUpdates:(NSArray<YapDatabaseViewRowChange *> *)rowChanges
|
||||||
oldViewItemCount:(NSUInteger)oldViewItemCount
|
oldViewItemCount:(NSUInteger)oldViewItemCount
|
||||||
{
|
{
|
||||||
OWSAssert(rowChanges);
|
OWSAssert(rowChanges);
|
||||||
|
|
||||||
|
// for (YapDatabaseViewRowChange *rowChange in rowChanges) {
|
||||||
|
// switch (rowChange.type) {
|
||||||
|
// case YapDatabaseViewChangeDelete:
|
||||||
|
// DDLogVerbose(@"...YapDatabaseViewChangeDelete: %@, %@, %zd",
|
||||||
|
// rowChange.collectionKey,
|
||||||
|
// rowChange.indexPath,
|
||||||
|
// rowChange.finalIndex);
|
||||||
|
// [DDLog flushLog];
|
||||||
|
// break;
|
||||||
|
// case YapDatabaseViewChangeInsert:
|
||||||
|
// DDLogVerbose(@"...YapDatabaseViewChangeInsert: %@, %@, %zd",
|
||||||
|
// rowChange.collectionKey,
|
||||||
|
// rowChange.newIndexPath,
|
||||||
|
// rowChange.finalIndex);
|
||||||
|
// [DDLog flushLog];
|
||||||
|
// break;
|
||||||
|
// case YapDatabaseViewChangeMove:
|
||||||
|
// DDLogVerbose(@"...YapDatabaseViewChangeMove: %@, %@, %@, %zd",
|
||||||
|
// rowChange.collectionKey,
|
||||||
|
// rowChange.indexPath,
|
||||||
|
// rowChange.newIndexPath,
|
||||||
|
// rowChange.finalIndex);
|
||||||
|
// [DDLog flushLog];
|
||||||
|
// break;
|
||||||
|
// case YapDatabaseViewChangeUpdate:
|
||||||
|
// DDLogVerbose(@"...YapDatabaseViewChangeUpdate: %@, %@, %zd",
|
||||||
|
// rowChange.collectionKey,
|
||||||
|
// rowChange.indexPath,
|
||||||
|
// rowChange.finalIndex);
|
||||||
|
// [DDLog flushLog];
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
// If user sends a new outgoing message, don't animate the change.
|
// If user sends a new outgoing message, don't animate the change.
|
||||||
BOOL isOnlyInsertingNewOutgoingMessages = YES;
|
BOOL isOnlyInsertingNewOutgoingMessages = YES;
|
||||||
BOOL isOnlyUpdatingLastOutgoingMessage = YES;
|
BOOL isOnlyUpdatingLastOutgoingMessage = YES;
|
||||||
|
@ -3325,20 +3437,23 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
|
||||||
[self presentViewController:actionSheetController animated:true completion:nil];
|
[self presentViewController:actionSheetController animated:true completion:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSIndexPath *)lastVisibleIndexPath
|
- (nullable NSIndexPath *)lastVisibleIndexPath
|
||||||
{
|
{
|
||||||
NSIndexPath *lastVisibleIndexPath = nil;
|
NSIndexPath *_Nullable lastVisibleIndexPath = nil;
|
||||||
for (NSIndexPath *indexPath in [self.collectionView indexPathsForVisibleItems]) {
|
for (NSIndexPath *indexPath in [self.collectionView indexPathsForVisibleItems]) {
|
||||||
if (!lastVisibleIndexPath || indexPath.row > lastVisibleIndexPath.row) {
|
if (!lastVisibleIndexPath || indexPath.row > lastVisibleIndexPath.row) {
|
||||||
lastVisibleIndexPath = indexPath;
|
lastVisibleIndexPath = indexPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (lastVisibleIndexPath && lastVisibleIndexPath.row >= self.viewItems.count) {
|
||||||
|
return (self.viewItems.count > 0 ? [NSIndexPath indexPathForRow:self.viewItems.count - 1 inSection:0] : nil);
|
||||||
|
}
|
||||||
return lastVisibleIndexPath;
|
return lastVisibleIndexPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (nullable ConversationViewItem *)lastVisibleViewItem
|
- (nullable ConversationViewItem *)lastVisibleViewItem
|
||||||
{
|
{
|
||||||
NSIndexPath *lastVisibleIndexPath = [self lastVisibleIndexPath];
|
NSIndexPath *_Nullable lastVisibleIndexPath = [self lastVisibleIndexPath];
|
||||||
if (!lastVisibleIndexPath) {
|
if (!lastVisibleIndexPath) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType);
|
||||||
|
|
||||||
@property (nonatomic, weak) OWSAudioMessageView *lastAudioMessageView;
|
@property (nonatomic, weak) OWSAudioMessageView *lastAudioMessageView;
|
||||||
|
|
||||||
@property (nonatomic, nullable) NSNumber *audioDurationSeconds;
|
@property (nonatomic, readonly, nullable) NSNumber *audioDurationSeconds;
|
||||||
|
|
||||||
- (CGFloat)audioProgressSeconds;
|
- (CGFloat)audioProgressSeconds;
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
||||||
|
|
||||||
@property (nonatomic) AudioPlaybackState audioPlaybackState;
|
@property (nonatomic) AudioPlaybackState audioPlaybackState;
|
||||||
@property (nonatomic) CGFloat audioProgressSeconds;
|
@property (nonatomic) CGFloat audioProgressSeconds;
|
||||||
|
@property (nonatomic, nullable) NSNumber *audioDurationSeconds;
|
||||||
|
|
||||||
#pragma mark - View State
|
#pragma mark - View State
|
||||||
|
|
||||||
|
@ -251,9 +252,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
||||||
OWSAssert([NSThread isMainThread]);
|
OWSAssert([NSThread isMainThread]);
|
||||||
|
|
||||||
self.audioProgressSeconds = progress;
|
self.audioProgressSeconds = progress;
|
||||||
if (duration > 0) {
|
|
||||||
self.audioDurationSeconds = @(duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
[self.lastAudioMessageView updateContents];
|
[self.lastAudioMessageView updateContents];
|
||||||
}
|
}
|
||||||
|
@ -390,13 +388,19 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
||||||
self.messageCellType = OWSMessageCellType_GenericAttachment;
|
self.messageCellType = OWSMessageCellType_GenericAttachment;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.contentSize = [self.attachmentStream imageSizeWithoutTransaction];
|
self.contentSize = [self.attachmentStream imageSize];
|
||||||
if (self.contentSize.width <= 0 || self.contentSize.height <= 0) {
|
if (self.contentSize.width <= 0 || self.contentSize.height <= 0) {
|
||||||
self.messageCellType = OWSMessageCellType_GenericAttachment;
|
self.messageCellType = OWSMessageCellType_GenericAttachment;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if ([self.attachmentStream isAudio]) {
|
} else if ([self.attachmentStream isAudio]) {
|
||||||
self.messageCellType = OWSMessageCellType_Audio;
|
CGFloat audioDurationSeconds = [self.attachmentStream audioDurationSeconds];
|
||||||
|
if (audioDurationSeconds > 0) {
|
||||||
|
self.audioDurationSeconds = @(audioDurationSeconds);
|
||||||
|
self.messageCellType = OWSMessageCellType_Audio;
|
||||||
|
} else {
|
||||||
|
self.messageCellType = OWSMessageCellType_GenericAttachment;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
self.messageCellType = OWSMessageCellType_GenericAttachment;
|
self.messageCellType = OWSMessageCellType_GenericAttachment;
|
||||||
|
|
|
@ -40,6 +40,14 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
OWSAssert(thread);
|
OWSAssert(thread);
|
||||||
|
|
||||||
NSMutableArray<OWSTableItem *> *items = [@[
|
NSMutableArray<OWSTableItem *> *items = [@[
|
||||||
|
[OWSTableItem itemWithTitle:@"Perform 100 random actions"
|
||||||
|
actionBlock:^{
|
||||||
|
[DebugUIMessages performRandomActions:100 thread:thread];
|
||||||
|
}],
|
||||||
|
[OWSTableItem itemWithTitle:@"Perform 1,000 random actions"
|
||||||
|
actionBlock:^{
|
||||||
|
[DebugUIMessages performRandomActions:1000 thread:thread];
|
||||||
|
}],
|
||||||
[OWSTableItem itemWithTitle:@"Send 10 messages (1/sec.)"
|
[OWSTableItem itemWithTitle:@"Send 10 messages (1/sec.)"
|
||||||
actionBlock:^{
|
actionBlock:^{
|
||||||
[DebugUIMessages sendTextMessages:10 thread:thread];
|
[DebugUIMessages sendTextMessages:10 thread:thread];
|
||||||
|
@ -241,14 +249,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
actionBlock:^{
|
actionBlock:^{
|
||||||
[DebugUIMessages injectFakeIncomingMessages:1000 thread:thread];
|
[DebugUIMessages injectFakeIncomingMessages:1000 thread:thread];
|
||||||
}],
|
}],
|
||||||
[OWSTableItem itemWithTitle:@"Perform 100 random actions"
|
|
||||||
actionBlock:^{
|
|
||||||
[DebugUIMessages performRandomActions:100 thread:thread];
|
|
||||||
}],
|
|
||||||
[OWSTableItem itemWithTitle:@"Perform 1,000 random actions"
|
|
||||||
actionBlock:^{
|
|
||||||
[DebugUIMessages performRandomActions:1000 thread:thread];
|
|
||||||
}],
|
|
||||||
] mutableCopy];
|
] mutableCopy];
|
||||||
if ([thread isKindOfClass:[TSContactThread class]]) {
|
if ([thread isKindOfClass:[TSContactThread class]]) {
|
||||||
TSContactThread *contactThread = (TSContactThread *)thread;
|
TSContactThread *contactThread = (TSContactThread *)thread;
|
||||||
|
@ -271,10 +271,14 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
+ (void)sendTextMessageInThread:(TSThread *)thread counter:(int)counter
|
+ (void)sendTextMessageInThread:(TSThread *)thread counter:(int)counter
|
||||||
{
|
{
|
||||||
|
DDLogInfo(@"%@ sendTextMessageInThread: %d", self.logTag, counter);
|
||||||
|
[DDLog flushLog];
|
||||||
|
|
||||||
NSString *randomText = [self randomText];
|
NSString *randomText = [self randomText];
|
||||||
NSString *text = [[[@(counter) description] stringByAppendingString:@" "] stringByAppendingString:randomText];
|
NSString *text = [[[@(counter) description] stringByAppendingString:@" "] stringByAppendingString:randomText];
|
||||||
OWSMessageSender *messageSender = [Environment getCurrent].messageSender;
|
OWSMessageSender *messageSender = [Environment getCurrent].messageSender;
|
||||||
[ThreadUtil sendMessageWithText:text inThread:thread messageSender:messageSender];
|
TSOutgoingMessage *message = [ThreadUtil sendMessageWithText:text inThread:thread messageSender:messageSender];
|
||||||
|
DDLogError(@"%@ sendTextMessageInThread timestamp: %llu.", self.logTag, message.timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)sendTextMessages:(int)counter thread:(TSThread *)thread
|
+ (void)sendTextMessages:(int)counter thread:(TSThread *)thread
|
||||||
|
@ -939,83 +943,96 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
+ (void)sendFakeMessages:(NSUInteger)counter thread:(TSThread *)thread
|
+ (void)sendFakeMessages:(NSUInteger)counter thread:(TSThread *)thread
|
||||||
{
|
{
|
||||||
[TSStorageManager.sharedManager.dbReadWriteConnection readWriteWithBlock:^(
|
[TSStorageManager.sharedManager.dbReadWriteConnection
|
||||||
YapDatabaseReadWriteTransaction *transaction) {
|
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||||
for (NSUInteger i = 0; i < counter; i++) {
|
[self sendFakeMessages:counter thread:thread transaction:transaction];
|
||||||
NSString *randomText = [self randomText];
|
}];
|
||||||
switch (arc4random_uniform(4)) {
|
}
|
||||||
case 0: {
|
|
||||||
TSIncomingMessage *message =
|
|
||||||
[[TSIncomingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
|
||||||
inThread:thread
|
|
||||||
authorId:@"+19174054215"
|
|
||||||
sourceDeviceId:0
|
|
||||||
messageBody:randomText];
|
|
||||||
[message markAsReadWithTransaction:transaction sendReadReceipt:NO updateExpiration:NO];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1: {
|
|
||||||
TSOutgoingMessage *message =
|
|
||||||
[[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
|
||||||
inThread:thread
|
|
||||||
messageBody:randomText];
|
|
||||||
[message saveWithTransaction:transaction];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 2: {
|
|
||||||
UInt32 filesize = 64;
|
|
||||||
TSAttachmentPointer *pointer =
|
|
||||||
[[TSAttachmentPointer alloc] initWithServerId:237391539706350548
|
|
||||||
key:[self createRandomNSDataOfSize:filesize]
|
|
||||||
digest:nil
|
|
||||||
byteCount:filesize
|
|
||||||
contentType:@"audio/mp3"
|
|
||||||
relay:@""
|
|
||||||
sourceFilename:@"test.mp3"
|
|
||||||
attachmentType:TSAttachmentTypeDefault];
|
|
||||||
[pointer saveWithTransaction:transaction];
|
|
||||||
TSIncomingMessage *message =
|
|
||||||
[[TSIncomingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
|
||||||
inThread:thread
|
|
||||||
authorId:@"+19174054215"
|
|
||||||
sourceDeviceId:0
|
|
||||||
messageBody:nil
|
|
||||||
attachmentIds:@[
|
|
||||||
pointer.uniqueId,
|
|
||||||
]
|
|
||||||
expiresInSeconds:0];
|
|
||||||
[message markAsReadWithTransaction:transaction sendReadReceipt:NO updateExpiration:NO];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 3: {
|
|
||||||
TSOutgoingMessage *message =
|
|
||||||
[[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
|
||||||
inThread:thread
|
|
||||||
isVoiceMessage:NO
|
|
||||||
expiresInSeconds:0];
|
|
||||||
|
|
||||||
NSString *filename = @"test.mp3";
|
+ (void)sendFakeMessages:(NSUInteger)counter
|
||||||
UInt32 filesize = 16;
|
thread:(TSThread *)thread
|
||||||
|
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||||
|
{
|
||||||
|
DDLogInfo(@"%@ sendFakeMessages: %zd", self.logTag, counter);
|
||||||
|
|
||||||
TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:@"audio/mp3"
|
for (NSUInteger i = 0; i < counter; i++) {
|
||||||
byteCount:filesize
|
NSString *randomText = [self randomText];
|
||||||
sourceFilename:filename];
|
switch (arc4random_uniform(4)) {
|
||||||
|
case 0: {
|
||||||
|
TSIncomingMessage *message =
|
||||||
|
[[TSIncomingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||||
|
inThread:thread
|
||||||
|
authorId:@"+19174054215"
|
||||||
|
sourceDeviceId:0
|
||||||
|
messageBody:randomText];
|
||||||
|
DDLogError(@"%@ sendFakeMessages incoming timestamp: %llu.", self.logTag, message.timestamp);
|
||||||
|
[message markAsReadWithTransaction:transaction sendReadReceipt:NO updateExpiration:NO];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1: {
|
||||||
|
TSOutgoingMessage *message =
|
||||||
|
[[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||||
|
inThread:thread
|
||||||
|
messageBody:randomText];
|
||||||
|
DDLogError(@"%@ sendFakeMessages outgoing timestamp: %llu.", self.logTag, message.timestamp);
|
||||||
|
[message saveWithTransaction:transaction];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
UInt32 filesize = 64;
|
||||||
|
TSAttachmentPointer *pointer =
|
||||||
|
[[TSAttachmentPointer alloc] initWithServerId:237391539706350548
|
||||||
|
key:[self createRandomNSDataOfSize:filesize]
|
||||||
|
digest:nil
|
||||||
|
byteCount:filesize
|
||||||
|
contentType:@"audio/mp3"
|
||||||
|
relay:@""
|
||||||
|
sourceFilename:@"test.mp3"
|
||||||
|
attachmentType:TSAttachmentTypeDefault];
|
||||||
|
[pointer saveWithTransaction:transaction];
|
||||||
|
TSIncomingMessage *message =
|
||||||
|
[[TSIncomingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||||
|
inThread:thread
|
||||||
|
authorId:@"+19174054215"
|
||||||
|
sourceDeviceId:0
|
||||||
|
messageBody:nil
|
||||||
|
attachmentIds:@[
|
||||||
|
pointer.uniqueId,
|
||||||
|
]
|
||||||
|
expiresInSeconds:0];
|
||||||
|
DDLogError(@"%@ sendFakeMessages incoming attachment timestamp: %llu.", self.logTag, message.timestamp);
|
||||||
|
[message markAsReadWithTransaction:transaction sendReadReceipt:NO updateExpiration:NO];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
TSOutgoingMessage *message =
|
||||||
|
[[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||||
|
inThread:thread
|
||||||
|
isVoiceMessage:NO
|
||||||
|
expiresInSeconds:0];
|
||||||
|
DDLogError(@"%@ sendFakeMessages outgoing attachment timestamp: %llu.", self.logTag, message.timestamp);
|
||||||
|
|
||||||
NSError *error;
|
NSString *filename = @"test.mp3";
|
||||||
BOOL success = [attachmentStream writeData:[self createRandomNSDataOfSize:filesize] error:&error];
|
UInt32 filesize = 16;
|
||||||
OWSAssert(success && !error);
|
|
||||||
|
|
||||||
[attachmentStream saveWithTransaction:transaction];
|
TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:@"audio/mp3"
|
||||||
[message.attachmentIds addObject:attachmentStream.uniqueId];
|
byteCount:filesize
|
||||||
if (filename) {
|
sourceFilename:filename];
|
||||||
message.attachmentFilenameMap[attachmentStream.uniqueId] = filename;
|
|
||||||
}
|
NSError *error;
|
||||||
[message saveWithTransaction:transaction];
|
BOOL success = [attachmentStream writeData:[self createRandomNSDataOfSize:filesize] error:&error];
|
||||||
break;
|
OWSAssert(success && !error);
|
||||||
|
|
||||||
|
[attachmentStream saveWithTransaction:transaction];
|
||||||
|
[message.attachmentIds addObject:attachmentStream.uniqueId];
|
||||||
|
if (filename) {
|
||||||
|
message.attachmentFilenameMap[attachmentStream.uniqueId] = filename;
|
||||||
}
|
}
|
||||||
|
[message saveWithTransaction:transaction];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}];
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)sendTinyAttachments:(int)counter thread:(TSThread *)thread
|
+ (void)sendTinyAttachments:(int)counter thread:(TSThread *)thread
|
||||||
|
@ -1099,6 +1116,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
{
|
{
|
||||||
OWSAssert(thread);
|
OWSAssert(thread);
|
||||||
|
|
||||||
|
DDLogInfo(@"%@ injectIncomingMessageInThread: %d", self.logTag, counter);
|
||||||
|
|
||||||
NSString *randomText = [self randomText];
|
NSString *randomText = [self randomText];
|
||||||
NSString *text = [[[@(counter) description] stringByAppendingString:@" "] stringByAppendingString:randomText];
|
NSString *text = [[[@(counter) description] stringByAppendingString:@" "] stringByAppendingString:randomText];
|
||||||
|
|
||||||
|
@ -1154,144 +1173,151 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
+ (void)performRandomActionInThread:(TSThread *)thread
|
+ (void)performRandomActionInThread:(TSThread *)thread
|
||||||
counter:(int)counter
|
counter:(int)counter
|
||||||
{
|
{
|
||||||
typedef void (^ActionBlock)(void);
|
typedef void (^ActionBlock)(YapDatabaseReadWriteTransaction *transaction);
|
||||||
NSArray<ActionBlock> *actionBlocks = @[
|
NSArray<ActionBlock> *actionBlocks = @[
|
||||||
^{
|
^(YapDatabaseReadWriteTransaction *transaction) {
|
||||||
[self injectIncomingMessageInThread:thread counter:counter];
|
// injectIncomingMessageInThread doesn't take a transaction.
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[self injectIncomingMessageInThread:thread counter:counter];
|
||||||
|
});
|
||||||
},
|
},
|
||||||
^{
|
^(YapDatabaseReadWriteTransaction *transaction) {
|
||||||
[self sendTextMessageInThread:thread counter:counter];
|
// sendTextMessageInThread doesn't take a transaction.
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[self sendTextMessageInThread:thread counter:counter];
|
||||||
|
});
|
||||||
},
|
},
|
||||||
^{
|
^(YapDatabaseReadWriteTransaction *transaction) {
|
||||||
NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4));
|
NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4));
|
||||||
[self sendFakeMessages:messageCount thread:thread];
|
[self sendFakeMessages:messageCount thread:thread transaction:transaction];
|
||||||
},
|
},
|
||||||
^{
|
^(YapDatabaseReadWriteTransaction *transaction) {
|
||||||
NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4));
|
NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4));
|
||||||
[self deleteRandomMessages:messageCount thread:thread];
|
[self deleteRandomMessages:messageCount thread:thread transaction:transaction];
|
||||||
},
|
},
|
||||||
^{
|
^(YapDatabaseReadWriteTransaction *transaction) {
|
||||||
NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4));
|
NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4));
|
||||||
[self deleteLastMessages:messageCount thread:thread];
|
[self deleteLastMessages:messageCount thread:thread transaction:transaction];
|
||||||
},
|
},
|
||||||
^{
|
^(YapDatabaseReadWriteTransaction *transaction) {
|
||||||
NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4));
|
NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4));
|
||||||
[self deleteRandomRecentMessages:messageCount thread:thread];
|
[self deleteRandomRecentMessages:messageCount thread:thread transaction:transaction];
|
||||||
},
|
},
|
||||||
^{
|
^(YapDatabaseReadWriteTransaction *transaction) {
|
||||||
NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4));
|
NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4));
|
||||||
[self insertAndDeleteNewOutgoingMessages:messageCount thread:thread];
|
[self insertAndDeleteNewOutgoingMessages:messageCount thread:thread transaction:transaction];
|
||||||
},
|
},
|
||||||
^{
|
^(YapDatabaseReadWriteTransaction *transaction) {
|
||||||
NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4));
|
NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4));
|
||||||
[self resurrectNewOutgoingMessages1:messageCount thread:thread];
|
[self resurrectNewOutgoingMessages1:messageCount thread:thread transaction:transaction];
|
||||||
},
|
},
|
||||||
^{
|
^(YapDatabaseReadWriteTransaction *transaction) {
|
||||||
NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4));
|
NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4));
|
||||||
[self resurrectNewOutgoingMessages2:messageCount thread:thread];
|
[self resurrectNewOutgoingMessages2:messageCount thread:thread transaction:transaction];
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
ActionBlock actionBlock = actionBlocks[(NSUInteger) arc4random_uniform((uint32_t) actionBlocks.count)];
|
[TSStorageManager.sharedManager.dbReadWriteConnection
|
||||||
actionBlock();
|
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||||
|
int actionCount = 1 + (int)arc4random_uniform(3);
|
||||||
|
for (int actionIdx = 0; actionIdx < actionCount; actionIdx++) {
|
||||||
|
ActionBlock actionBlock = actionBlocks[(NSUInteger)arc4random_uniform((uint32_t)actionBlocks.count)];
|
||||||
|
actionBlock(transaction);
|
||||||
|
}
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)deleteRandomMessages:(NSUInteger)count thread:(TSThread *)thread
|
+ (void)deleteRandomMessages:(NSUInteger)count
|
||||||
|
thread:(TSThread *)thread
|
||||||
|
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||||
{
|
{
|
||||||
DDLogInfo(@"%@ deleteRandomMessages: %zd", self.logTag, count);
|
DDLogInfo(@"%@ deleteRandomMessages: %zd", self.logTag, count);
|
||||||
|
|
||||||
[TSStorageManager.sharedManager.dbReadWriteConnection readWriteWithBlock:^(
|
YapDatabaseViewTransaction *interactionsByThread = [transaction ext:TSMessageDatabaseViewExtensionName];
|
||||||
YapDatabaseReadWriteTransaction *transaction) {
|
NSUInteger messageCount = [interactionsByThread numberOfItemsInGroup:thread.uniqueId];
|
||||||
|
|
||||||
YapDatabaseViewTransaction *interactionsByThread = [transaction ext:TSMessageDatabaseViewExtensionName];
|
NSMutableArray<NSNumber *> *messageIndices = [NSMutableArray new];
|
||||||
NSUInteger messageCount = [interactionsByThread numberOfItemsInGroup:thread.uniqueId];
|
for (NSUInteger messageIdx = 0; messageIdx < messageCount; messageIdx++) {
|
||||||
|
[messageIndices addObject:@(messageIdx)];
|
||||||
|
}
|
||||||
|
NSMutableArray<TSInteraction *> *interactions = [NSMutableArray new];
|
||||||
|
for (NSUInteger i = 0; i < count && messageIndices.count > 0; i++) {
|
||||||
|
NSUInteger idx = (NSUInteger)arc4random_uniform((uint32_t)messageIndices.count);
|
||||||
|
NSNumber *messageIdx = messageIndices[idx];
|
||||||
|
[messageIndices removeObjectAtIndex:idx];
|
||||||
|
|
||||||
NSMutableArray<NSNumber *> *messageIndices = [NSMutableArray new];
|
TSInteraction *_Nullable interaction =
|
||||||
for (NSUInteger messageIdx =0; messageIdx < messageCount; messageIdx++) {
|
|
||||||
[messageIndices addObject:@(messageIdx)];
|
|
||||||
}
|
|
||||||
NSMutableArray<TSInteraction *> *interactions = [NSMutableArray new];
|
|
||||||
for (NSUInteger i =0; i < count && messageIndices.count > 0; i++) {
|
|
||||||
NSUInteger idx = (NSUInteger) arc4random_uniform((uint32_t) messageIndices.count);
|
|
||||||
NSNumber *messageIdx = messageIndices[idx];
|
|
||||||
[messageIndices removeObjectAtIndex:idx];
|
|
||||||
|
|
||||||
TSInteraction *_Nullable interaction =
|
|
||||||
[interactionsByThread objectAtIndex:messageIdx.unsignedIntegerValue inGroup:thread.uniqueId];
|
[interactionsByThread objectAtIndex:messageIdx.unsignedIntegerValue inGroup:thread.uniqueId];
|
||||||
OWSAssert(interaction);
|
OWSAssert(interaction);
|
||||||
[interactions addObject:interaction];
|
[interactions addObject:interaction];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (TSInteraction *interaction in interactions) {
|
for (TSInteraction *interaction in interactions) {
|
||||||
[interaction removeWithTransaction:transaction];
|
[interaction removeWithTransaction:transaction];
|
||||||
}
|
}
|
||||||
}];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)deleteLastMessages:(NSUInteger)count thread:(TSThread *)thread
|
+ (void)deleteLastMessages:(NSUInteger)count
|
||||||
|
thread:(TSThread *)thread
|
||||||
|
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||||
{
|
{
|
||||||
DDLogInfo(@"%@ deleteLastMessages", self.logTag);
|
DDLogInfo(@"%@ deleteLastMessages", self.logTag);
|
||||||
|
|
||||||
|
YapDatabaseViewTransaction *interactionsByThread = [transaction ext:TSMessageDatabaseViewExtensionName];
|
||||||
|
NSUInteger messageCount = (NSUInteger)[interactionsByThread numberOfItemsInGroup:thread.uniqueId];
|
||||||
|
|
||||||
[TSStorageManager.sharedManager.dbReadWriteConnection readWriteWithBlock:^(
|
NSMutableArray<NSNumber *> *messageIndices = [NSMutableArray new];
|
||||||
YapDatabaseReadWriteTransaction *transaction) {
|
for (NSUInteger i = 0; i < count && i < messageCount; i++) {
|
||||||
|
NSUInteger messageIdx = messageCount - (1 + i);
|
||||||
YapDatabaseViewTransaction *interactionsByThread = [transaction ext:TSMessageDatabaseViewExtensionName];
|
[messageIndices addObject:@(messageIdx)];
|
||||||
NSUInteger messageCount = (NSInteger)[interactionsByThread numberOfItemsInGroup:thread.uniqueId];
|
}
|
||||||
|
NSMutableArray<TSInteraction *> *interactions = [NSMutableArray new];
|
||||||
NSMutableArray<NSNumber *> *messageIndices = [NSMutableArray new];
|
for (NSNumber *messageIdx in messageIndices) {
|
||||||
for (NSUInteger i = 0; i < count && i < messageCount; i++) {
|
TSInteraction *_Nullable interaction =
|
||||||
NSUInteger messageIdx = messageCount - (1 + i);
|
[interactionsByThread objectAtIndex:messageIdx.unsignedIntegerValue inGroup:thread.uniqueId];
|
||||||
[messageIndices addObject:@(messageIdx)];
|
OWSAssert(interaction);
|
||||||
}
|
[interactions addObject:interaction];
|
||||||
NSMutableArray<TSInteraction *> *interactions = [NSMutableArray new];
|
}
|
||||||
for (NSNumber *messageIdx in messageIndices) {
|
for (TSInteraction *interaction in interactions) {
|
||||||
TSInteraction *_Nullable interaction =
|
[interaction removeWithTransaction:transaction];
|
||||||
[interactionsByThread objectAtIndex:messageIdx.unsignedIntegerValue inGroup:thread.uniqueId];
|
}
|
||||||
OWSAssert(interaction);
|
|
||||||
[interactions addObject:interaction];
|
|
||||||
}
|
|
||||||
for (TSInteraction *interaction in interactions) {
|
|
||||||
[interaction removeWithTransaction:transaction];
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)deleteRandomRecentMessages:(NSUInteger)count thread:(TSThread *)thread
|
+ (void)deleteRandomRecentMessages:(NSUInteger)count
|
||||||
|
thread:(TSThread *)thread
|
||||||
|
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||||
{
|
{
|
||||||
DDLogInfo(@"%@ deleteRandomRecentMessages: %zd", self.logTag, count);
|
DDLogInfo(@"%@ deleteRandomRecentMessages: %zd", self.logTag, count);
|
||||||
|
|
||||||
[TSStorageManager.sharedManager.dbReadWriteConnection readWriteWithBlock:^(
|
YapDatabaseViewTransaction *interactionsByThread = [transaction ext:TSMessageDatabaseViewExtensionName];
|
||||||
YapDatabaseReadWriteTransaction *transaction) {
|
NSInteger messageCount = (NSInteger)[interactionsByThread numberOfItemsInGroup:thread.uniqueId];
|
||||||
|
|
||||||
YapDatabaseViewTransaction *interactionsByThread = [transaction ext:TSMessageDatabaseViewExtensionName];
|
NSMutableArray<NSNumber *> *messageIndices = [NSMutableArray new];
|
||||||
NSInteger messageCount = (NSInteger) [interactionsByThread numberOfItemsInGroup:thread.uniqueId];
|
const NSInteger kRecentMessageCount = 10;
|
||||||
|
for (NSInteger i = 0; i < kRecentMessageCount; i++) {
|
||||||
NSMutableArray<NSNumber *> *messageIndices = [NSMutableArray new];
|
NSInteger messageIdx = messageCount - (1 + i);
|
||||||
const NSInteger kRecentMessageCount = 10;
|
if (messageIdx >= 0) {
|
||||||
for (NSInteger i =0; i < kRecentMessageCount; i++) {
|
[messageIndices addObject:@(messageIdx)];
|
||||||
NSInteger messageIdx = messageCount - (1 + i);
|
|
||||||
if (messageIdx >= 0) {
|
|
||||||
[messageIndices addObject:@(messageIdx)];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
NSMutableArray<TSInteraction *> *interactions = [NSMutableArray new];
|
}
|
||||||
for (NSUInteger i =0; i < count && messageIndices.count > 0; i++) {
|
NSMutableArray<TSInteraction *> *interactions = [NSMutableArray new];
|
||||||
NSUInteger idx = (NSUInteger) arc4random_uniform((uint32_t) messageIndices.count);
|
for (NSUInteger i = 0; i < count && messageIndices.count > 0; i++) {
|
||||||
NSNumber *messageIdx = messageIndices[idx];
|
NSUInteger idx = (NSUInteger)arc4random_uniform((uint32_t)messageIndices.count);
|
||||||
[messageIndices removeObjectAtIndex:idx];
|
NSNumber *messageIdx = messageIndices[idx];
|
||||||
|
[messageIndices removeObjectAtIndex:idx];
|
||||||
|
|
||||||
TSInteraction *_Nullable interaction =
|
TSInteraction *_Nullable interaction =
|
||||||
[interactionsByThread objectAtIndex:messageIdx.unsignedIntegerValue inGroup:thread.uniqueId];
|
[interactionsByThread objectAtIndex:messageIdx.unsignedIntegerValue inGroup:thread.uniqueId];
|
||||||
OWSAssert(interaction);
|
OWSAssert(interaction);
|
||||||
[interactions addObject:interaction];
|
[interactions addObject:interaction];
|
||||||
}
|
}
|
||||||
for (TSInteraction *interaction in interactions) {
|
for (TSInteraction *interaction in interactions) {
|
||||||
[interaction removeWithTransaction:transaction];
|
[interaction removeWithTransaction:transaction];
|
||||||
}
|
}
|
||||||
}];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)insertAndDeleteNewOutgoingMessages:(NSUInteger)count thread:(TSThread *)thread
|
+ (void)insertAndDeleteNewOutgoingMessages:(NSUInteger)count
|
||||||
|
thread:(TSThread *)thread
|
||||||
|
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||||
{
|
{
|
||||||
DDLogInfo(@"%@ insertAndDeleteNewOutgoingMessages: %zd", self.logTag, count);
|
DDLogInfo(@"%@ insertAndDeleteNewOutgoingMessages: %zd", self.logTag, count);
|
||||||
|
|
||||||
|
@ -1299,28 +1325,28 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
for (NSUInteger i =0; i < count; i++) {
|
for (NSUInteger i =0; i < count; i++) {
|
||||||
NSString *text = [self randomText];
|
NSString *text = [self randomText];
|
||||||
OWSDisappearingMessagesConfiguration *configuration =
|
OWSDisappearingMessagesConfiguration *configuration =
|
||||||
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId];
|
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId transaction:transaction];
|
||||||
TSOutgoingMessage *message =
|
TSOutgoingMessage *message =
|
||||||
[[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
[[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||||
inThread:thread
|
inThread:thread
|
||||||
messageBody:text
|
messageBody:text
|
||||||
attachmentIds:[NSMutableArray new]
|
attachmentIds:[NSMutableArray new]
|
||||||
expiresInSeconds:(configuration.isEnabled ? configuration.durationSeconds : 0)];
|
expiresInSeconds:(configuration.isEnabled ? configuration.durationSeconds : 0)];
|
||||||
|
DDLogError(@"%@ insertAndDeleteNewOutgoingMessages timestamp: %llu.", self.logTag, message.timestamp);
|
||||||
[messages addObject:message];
|
[messages addObject:message];
|
||||||
}
|
}
|
||||||
|
|
||||||
[TSStorageManager.sharedManager.dbReadWriteConnection readWriteWithBlock:^(
|
for (TSOutgoingMessage *message in messages) {
|
||||||
YapDatabaseReadWriteTransaction *transaction) {
|
[message saveWithTransaction:transaction];
|
||||||
for (TSOutgoingMessage *message in messages) {
|
}
|
||||||
[message saveWithTransaction:transaction];
|
for (TSOutgoingMessage *message in messages) {
|
||||||
}
|
[message removeWithTransaction:transaction];
|
||||||
for (TSOutgoingMessage *message in messages) {
|
}
|
||||||
[message removeWithTransaction:transaction];
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)resurrectNewOutgoingMessages1:(NSUInteger)count thread:(TSThread *)thread
|
+ (void)resurrectNewOutgoingMessages1:(NSUInteger)count
|
||||||
|
thread:(TSThread *)thread
|
||||||
|
transaction:(YapDatabaseReadWriteTransaction *)initialTransaction
|
||||||
{
|
{
|
||||||
DDLogInfo(@"%@ resurrectNewOutgoingMessages1.1: %zd", self.logTag, count);
|
DDLogInfo(@"%@ resurrectNewOutgoingMessages1.1: %zd", self.logTag, count);
|
||||||
|
|
||||||
|
@ -1328,22 +1354,22 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
for (NSUInteger i =0; i < count; i++) {
|
for (NSUInteger i =0; i < count; i++) {
|
||||||
NSString *text = [self randomText];
|
NSString *text = [self randomText];
|
||||||
OWSDisappearingMessagesConfiguration *configuration =
|
OWSDisappearingMessagesConfiguration *configuration =
|
||||||
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId];
|
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId
|
||||||
|
transaction:initialTransaction];
|
||||||
TSOutgoingMessage *message =
|
TSOutgoingMessage *message =
|
||||||
[[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
[[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||||
inThread:thread
|
inThread:thread
|
||||||
messageBody:text
|
messageBody:text
|
||||||
attachmentIds:[NSMutableArray new]
|
attachmentIds:[NSMutableArray new]
|
||||||
expiresInSeconds:(configuration.isEnabled ? configuration.durationSeconds : 0)];
|
expiresInSeconds:(configuration.isEnabled ? configuration.durationSeconds : 0)];
|
||||||
|
DDLogError(@"%@ resurrectNewOutgoingMessages1 timestamp: %llu.", self.logTag, message.timestamp);
|
||||||
[messages addObject:message];
|
[messages addObject:message];
|
||||||
}
|
}
|
||||||
|
|
||||||
[TSStorageManager.sharedManager.dbReadWriteConnection readWriteWithBlock:^(
|
for (TSOutgoingMessage *message in messages) {
|
||||||
YapDatabaseReadWriteTransaction *transaction) {
|
[message saveWithTransaction:initialTransaction];
|
||||||
for (TSOutgoingMessage *message in messages) {
|
}
|
||||||
[message saveWithTransaction:transaction];
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||||
DDLogInfo(@"%@ resurrectNewOutgoingMessages1.2: %zd", self.logTag, count);
|
DDLogInfo(@"%@ resurrectNewOutgoingMessages1.2: %zd", self.logTag, count);
|
||||||
[TSStorageManager.sharedManager.dbReadWriteConnection
|
[TSStorageManager.sharedManager.dbReadWriteConnection
|
||||||
|
@ -1358,7 +1384,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)resurrectNewOutgoingMessages2:(NSUInteger)count thread:(TSThread *)thread
|
+ (void)resurrectNewOutgoingMessages2:(NSUInteger)count
|
||||||
|
thread:(TSThread *)thread
|
||||||
|
transaction:(YapDatabaseReadWriteTransaction *)initialTransaction
|
||||||
{
|
{
|
||||||
DDLogInfo(@"%@ resurrectNewOutgoingMessages2.1: %zd", self.logTag, count);
|
DDLogInfo(@"%@ resurrectNewOutgoingMessages2.1: %zd", self.logTag, count);
|
||||||
|
|
||||||
|
@ -1366,23 +1394,23 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
for (NSUInteger i =0; i < count; i++) {
|
for (NSUInteger i =0; i < count; i++) {
|
||||||
NSString *text = [self randomText];
|
NSString *text = [self randomText];
|
||||||
OWSDisappearingMessagesConfiguration *configuration =
|
OWSDisappearingMessagesConfiguration *configuration =
|
||||||
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId];
|
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId
|
||||||
|
transaction:initialTransaction];
|
||||||
TSOutgoingMessage *message =
|
TSOutgoingMessage *message =
|
||||||
[[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
[[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||||
inThread:thread
|
inThread:thread
|
||||||
messageBody:text
|
messageBody:text
|
||||||
attachmentIds:[NSMutableArray new]
|
attachmentIds:[NSMutableArray new]
|
||||||
expiresInSeconds:(configuration.isEnabled ? configuration.durationSeconds : 0)];
|
expiresInSeconds:(configuration.isEnabled ? configuration.durationSeconds : 0)];
|
||||||
|
DDLogError(@"%@ resurrectNewOutgoingMessages2 timestamp: %llu.", self.logTag, message.timestamp);
|
||||||
[messages addObject:message];
|
[messages addObject:message];
|
||||||
}
|
}
|
||||||
|
|
||||||
[TSStorageManager.sharedManager.dbReadWriteConnection readWriteWithBlock:^(
|
for (TSOutgoingMessage *message in messages) {
|
||||||
YapDatabaseReadWriteTransaction *transaction) {
|
[message updateWithMessageState:TSOutgoingMessageStateAttemptingOut transaction:initialTransaction];
|
||||||
for (TSOutgoingMessage *message in messages) {
|
[message saveWithTransaction:initialTransaction];
|
||||||
[message updateWithMessageState:TSOutgoingMessageStateAttemptingOut transaction:transaction];
|
}
|
||||||
[message saveWithTransaction:transaction];
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||||
DDLogInfo(@"%@ resurrectNewOutgoingMessages2.2: %zd", self.logTag, count);
|
DDLogInfo(@"%@ resurrectNewOutgoingMessages2.2: %zd", self.logTag, count);
|
||||||
[TSStorageManager.sharedManager.dbReadWriteConnection
|
[TSStorageManager.sharedManager.dbReadWriteConnection
|
||||||
|
|
|
@ -4,8 +4,10 @@
|
||||||
|
|
||||||
#import "DataSource.h"
|
#import "DataSource.h"
|
||||||
#import "TSAttachment.h"
|
#import "TSAttachment.h"
|
||||||
|
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
@ -51,11 +53,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
+ (void)deleteAttachments;
|
+ (void)deleteAttachments;
|
||||||
+ (NSString *)attachmentsFolder;
|
+ (NSString *)attachmentsFolder;
|
||||||
|
|
||||||
- (CGSize)imageSizeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
- (CGSize)imageSize;
|
||||||
- (CGSize)imageSizeWithoutTransaction;
|
|
||||||
|
|
||||||
- (CGFloat)audioDurationSecondsWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
- (CGFloat)audioDurationSeconds;
|
||||||
- (CGFloat)audioDurationSecondsWithoutTransaction;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
|
@ -396,7 +396,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGSize)ensureCachedImageSizeWithTransaction:(YapDatabaseReadWriteTransaction *_Nullable)transaction
|
- (CGSize)imageSize
|
||||||
{
|
{
|
||||||
OWSAssert([NSThread isMainThread]);
|
OWSAssert([NSThread isMainThread]);
|
||||||
|
|
||||||
|
@ -408,68 +408,48 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
self.cachedImageWidth = @(imageSize.width);
|
self.cachedImageWidth = @(imageSize.width);
|
||||||
self.cachedImageHeight = @(imageSize.height);
|
self.cachedImageHeight = @(imageSize.height);
|
||||||
|
|
||||||
void (^updateDataStore)() = ^(YapDatabaseReadWriteTransaction *transaction) {
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
OWSAssert(transaction);
|
|
||||||
|
|
||||||
NSString *collection = [[self class] collection];
|
|
||||||
TSAttachmentStream *latestInstance = [transaction objectForKey:self.uniqueId inCollection:collection];
|
|
||||||
if (latestInstance) {
|
|
||||||
latestInstance.cachedImageWidth = @(imageSize.width);
|
|
||||||
latestInstance.cachedImageHeight = @(imageSize.height);
|
|
||||||
[latestInstance saveWithTransaction:transaction];
|
|
||||||
} else {
|
|
||||||
// This message has not yet been saved; do nothing.
|
|
||||||
OWSFail(@"%@ Attachment not yet saved.", self.logTag);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (transaction) {
|
|
||||||
updateDataStore(transaction);
|
|
||||||
} else {
|
|
||||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||||
updateDataStore(transaction);
|
|
||||||
|
NSString *collection = [[self class] collection];
|
||||||
|
TSAttachmentStream *latestInstance = [transaction objectForKey:self.uniqueId inCollection:collection];
|
||||||
|
if (latestInstance) {
|
||||||
|
latestInstance.cachedImageWidth = @(imageSize.width);
|
||||||
|
latestInstance.cachedImageHeight = @(imageSize.height);
|
||||||
|
[latestInstance saveWithTransaction:transaction];
|
||||||
|
} else {
|
||||||
|
// This message has not yet been saved; do nothing.
|
||||||
|
OWSFail(@"%@ Attachment not yet saved.", self.logTag);
|
||||||
|
}
|
||||||
}];
|
}];
|
||||||
}
|
});
|
||||||
|
|
||||||
return imageSize;
|
return imageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGSize)imageSizeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
|
||||||
{
|
|
||||||
OWSAssert([NSThread isMainThread]);
|
|
||||||
OWSAssert(transaction);
|
|
||||||
|
|
||||||
return [self ensureCachedImageSizeWithTransaction:transaction];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGSize)imageSizeWithoutTransaction
|
|
||||||
{
|
|
||||||
OWSAssert([NSThread isMainThread]);
|
|
||||||
|
|
||||||
return [self ensureCachedImageSizeWithTransaction:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)calculateAudioDurationSeconds
|
- (CGFloat)calculateAudioDurationSeconds
|
||||||
{
|
{
|
||||||
OWSAssert([NSThread isMainThread]);
|
OWSAssert([NSThread isMainThread]);
|
||||||
OWSAssert([self isAudio]);
|
OWSAssert([self isAudio]);
|
||||||
|
|
||||||
NSError *error;
|
return 0;
|
||||||
AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:self.mediaURL error:&error];
|
|
||||||
if (error && [error.domain isEqualToString:NSOSStatusErrorDomain]
|
// NSError *error;
|
||||||
&& (error.code == kAudioFileInvalidFileError || error.code == kAudioFileStreamError_InvalidFile)) {
|
// AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:self.mediaURL error:&error];
|
||||||
// Ignore "invalid audio file" errors.
|
// if (error && [error.domain isEqualToString:NSOSStatusErrorDomain]
|
||||||
return 0.f;
|
// && (error.code == kAudioFileInvalidFileError || error.code == kAudioFileStreamError_InvalidFile)) {
|
||||||
}
|
// // Ignore "invalid audio file" errors.
|
||||||
if (!error) {
|
// return 0.f;
|
||||||
return (CGFloat)[audioPlayer duration];
|
// }
|
||||||
} else {
|
// if (!error) {
|
||||||
OWSFail(@"Could not find audio duration: %@", self.mediaURL);
|
// return (CGFloat)[audioPlayer duration];
|
||||||
return 0;
|
// } else {
|
||||||
}
|
// OWSFail(@"Could not find audio duration: %@", self.mediaURL);
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGFloat)ensureCachedAudioDurationSecondsWithTransaction:(YapDatabaseReadWriteTransaction *_Nullable)transaction
|
- (CGFloat)audioDurationSeconds
|
||||||
{
|
{
|
||||||
OWSAssert([NSThread isMainThread]);
|
OWSAssert([NSThread isMainThread]);
|
||||||
|
|
||||||
|
@ -480,46 +460,25 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
CGFloat audioDurationSeconds = [self calculateAudioDurationSeconds];
|
CGFloat audioDurationSeconds = [self calculateAudioDurationSeconds];
|
||||||
self.cachedAudioDurationSeconds = @(audioDurationSeconds);
|
self.cachedAudioDurationSeconds = @(audioDurationSeconds);
|
||||||
|
|
||||||
void (^updateDataStore)() = ^(YapDatabaseReadWriteTransaction *transaction) {
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
OWSAssert(transaction);
|
|
||||||
|
|
||||||
NSString *collection = [[self class] collection];
|
|
||||||
TSAttachmentStream *latestInstance = [transaction objectForKey:self.uniqueId inCollection:collection];
|
|
||||||
if (latestInstance) {
|
|
||||||
latestInstance.cachedAudioDurationSeconds = @(audioDurationSeconds);
|
|
||||||
[latestInstance saveWithTransaction:transaction];
|
|
||||||
} else {
|
|
||||||
// This message has not yet been saved; do nothing.
|
|
||||||
OWSFail(@"%@ Attachment not yet saved.", self.logTag);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (transaction) {
|
|
||||||
updateDataStore(transaction);
|
|
||||||
} else {
|
|
||||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||||
updateDataStore(transaction);
|
NSString *collection = [[self class] collection];
|
||||||
|
TSAttachmentStream *latestInstance = [transaction objectForKey:self.uniqueId inCollection:collection];
|
||||||
|
if (latestInstance) {
|
||||||
|
latestInstance.cachedAudioDurationSeconds = @(audioDurationSeconds);
|
||||||
|
[latestInstance saveWithTransaction:transaction];
|
||||||
|
} else {
|
||||||
|
// This message has not yet been saved or has been deleted; do nothing.
|
||||||
|
// This isn't an error per se, but these race conditions should be
|
||||||
|
// _very_ rare.
|
||||||
|
OWSFail(@"%@ Attachment not yet saved.", self.logTag);
|
||||||
|
}
|
||||||
}];
|
}];
|
||||||
}
|
});
|
||||||
|
|
||||||
return audioDurationSeconds;
|
return audioDurationSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGFloat)audioDurationSecondsWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
|
||||||
{
|
|
||||||
OWSAssert([NSThread isMainThread]);
|
|
||||||
OWSAssert(transaction);
|
|
||||||
|
|
||||||
return [self ensureCachedAudioDurationSecondsWithTransaction:transaction];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)audioDurationSecondsWithoutTransaction
|
|
||||||
{
|
|
||||||
OWSAssert([NSThread isMainThread]);
|
|
||||||
|
|
||||||
return [self ensureCachedAudioDurationSecondsWithTransaction:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
|
@ -363,7 +363,9 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE
|
||||||
= (NSArray<TSOutgoingMessage *> *)[TSInteraction interactionsWithTimestamp:sentTimestamp
|
= (NSArray<TSOutgoingMessage *> *)[TSInteraction interactionsWithTimestamp:sentTimestamp
|
||||||
ofClass:[TSOutgoingMessage class]
|
ofClass:[TSOutgoingMessage class]
|
||||||
withTransaction:transaction];
|
withTransaction:transaction];
|
||||||
OWSAssert(messages.count <= 1);
|
if (messages.count > 1) {
|
||||||
|
OWSFail(@"%@ More than one matching message with timestamp: %llu.", self.logTag, sentTimestamp);
|
||||||
|
}
|
||||||
if (messages.count > 0) {
|
if (messages.count > 0) {
|
||||||
// TODO: We might also need to "mark as read by recipient" any older messages
|
// TODO: We might also need to "mark as read by recipient" any older messages
|
||||||
// from us in that thread. Or maybe this state should hang on the thread?
|
// from us in that thread. Or maybe this state should hang on the thread?
|
||||||
|
|
Loading…
Reference in a new issue