Elaborate debug UI for messages.

This commit is contained in:
Matthew Chen 2018-03-26 10:45:52 -04:00
parent 469fb2644f
commit 041b28dd79
8 changed files with 908 additions and 802 deletions

View File

@ -206,6 +206,8 @@
34D2CCD4206294B900CB1A14 /* OWSScreenLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D2CCD3206294B900CB1A14 /* OWSScreenLock.swift */; };
34D2CCDA2062E7D000CB1A14 /* OWSScreenLockUI.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D2CCD92062E7D000CB1A14 /* OWSScreenLockUI.m */; };
34D2CCD220618B3000CB1A14 /* OWSBackupLazyRestoreJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D2CCD120618B2F00CB1A14 /* OWSBackupLazyRestoreJob.swift */; };
34D2CCDF206939B400CB1A14 /* DebugUIMessagesAction.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D2CCDB206939B100CB1A14 /* DebugUIMessagesAction.m */; };
34D2CCE0206939B400CB1A14 /* DebugUIMessagesAssetLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D2CCDC206939B200CB1A14 /* DebugUIMessagesAssetLoader.m */; };
34D5CCA91EAE3D30005515DB /* AvatarViewHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */; };
34D8C0271ED3673300188D7C /* DebugUIMessages.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D8C0241ED3673300188D7C /* DebugUIMessages.m */; };
34D8C0281ED3673300188D7C /* DebugUITableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D8C0261ED3673300188D7C /* DebugUITableViewController.m */; };
@ -814,6 +816,11 @@
34D2CCD82062E7D000CB1A14 /* OWSScreenLockUI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSScreenLockUI.h; sourceTree = "<group>"; };
34D2CCD92062E7D000CB1A14 /* OWSScreenLockUI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSScreenLockUI.m; sourceTree = "<group>"; };
34D2CCD120618B2F00CB1A14 /* OWSBackupLazyRestoreJob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSBackupLazyRestoreJob.swift; sourceTree = "<group>"; };
34D2CCDB206939B100CB1A14 /* DebugUIMessagesAction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUIMessagesAction.m; sourceTree = "<group>"; };
34D2CCDC206939B200CB1A14 /* DebugUIMessagesAssetLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUIMessagesAssetLoader.m; sourceTree = "<group>"; };
34D2CCDD206939B200CB1A14 /* DebugUIMessagesAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIMessagesAction.h; sourceTree = "<group>"; };
34D2CCDE206939B400CB1A14 /* DebugUIMessagesAssetLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIMessagesAssetLoader.h; sourceTree = "<group>"; };
34D2CCE220693A1700CB1A14 /* DebugUIMessagesUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIMessagesUtils.h; sourceTree = "<group>"; };
34D5CCA71EAE3D30005515DB /* AvatarViewHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AvatarViewHelper.h; sourceTree = "<group>"; };
34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AvatarViewHelper.m; sourceTree = "<group>"; };
34D8C0231ED3673300188D7C /* DebugUIMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIMessages.h; sourceTree = "<group>"; };
@ -1676,6 +1683,11 @@
45B27B852037FFB400A539DF /* DebugUIFileBrowser.swift */,
34D8C0231ED3673300188D7C /* DebugUIMessages.h */,
34D8C0241ED3673300188D7C /* DebugUIMessages.m */,
34D2CCDD206939B200CB1A14 /* DebugUIMessagesAction.h */,
34D2CCDB206939B100CB1A14 /* DebugUIMessagesAction.m */,
34D2CCDE206939B400CB1A14 /* DebugUIMessagesAssetLoader.h */,
34D2CCDC206939B200CB1A14 /* DebugUIMessagesAssetLoader.m */,
34D2CCE220693A1700CB1A14 /* DebugUIMessagesUtils.h */,
341F2C0D1F2B8AE700D07D6B /* DebugUIMisc.h */,
341F2C0E1F2B8AE700D07D6B /* DebugUIMisc.m */,
457C87B72032645C008D52D6 /* DebugUINotifications.swift */,
@ -3137,6 +3149,7 @@
34CCAF381F0C0599004084F4 /* AppUpdateNag.m in Sources */,
EF764C351DB67CC5000D9A87 /* UIViewController+Permissions.m in Sources */,
45CD81EF1DC030E7004C9430 /* SyncPushTokensJob.swift in Sources */,
34D2CCE0206939B400CB1A14 /* DebugUIMessagesAssetLoader.m in Sources */,
45794E861E00620000066731 /* CallUIAdapter.swift in Sources */,
340FC8BA204DAC8D007AEB0F /* FingerprintViewScanController.m in Sources */,
4585C4681ED8F8D200896AEA /* SafetyNumberConfirmationAlert.swift in Sources */,
@ -3246,6 +3259,7 @@
3461299C1FD1EA9E00532771 /* NotificationsManager.m in Sources */,
4521C3C01F59F3BA00B4C582 /* TextFieldHelper.swift in Sources */,
34B3F87E1E8DF1700035BE1A /* InboxTableViewCell.m in Sources */,
34D2CCDF206939B400CB1A14 /* DebugUIMessagesAction.m in Sources */,
340FC8AC204DAC8D007AEB0F /* PrivacySettingsTableViewController.m in Sources */,
34D2CCD4206294B900CB1A14 /* OWSScreenLock.swift in Sources */,
340FC8C5204DE223007AEB0F /* DebugUIBackup.m in Sources */,

View File

@ -1,13 +1,11 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "DebugUIPage.h"
NS_ASSUME_NONNULL_BEGIN
@class TSThread;
@interface DebugUIMessages : DebugUIPage
@end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,62 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "DebugUIMessagesUtils.h"
NS_ASSUME_NONNULL_BEGIN
@interface DebugUIMessagesAction : NSObject
@property (nonatomic) NSString *label;
- (void)prepareAndPerformNTimes:(NSUInteger)count;
@end
#pragma mark -
@interface DebugUIMessagesSingleAction : DebugUIMessagesAction
+ (DebugUIMessagesAction *)actionWithLabel:(NSString *)label
staggeredActionBlock:(StaggeredActionBlock)staggeredActionBlock;
+ (DebugUIMessagesAction *)actionWithLabel:(NSString *)label
unstaggeredActionBlock:(UnstaggeredActionBlock)unstaggeredActionBlock;
+ (DebugUIMessagesAction *)actionWithLabel:(NSString *)label
staggeredActionBlock:(StaggeredActionBlock)staggeredActionBlock
prepareBlock:(ActionPrepareBlock)prepareBlock;
+ (DebugUIMessagesAction *)actionWithLabel:(NSString *)label
unstaggeredActionBlock:(UnstaggeredActionBlock)unstaggeredActionBlock
prepareBlock:(ActionPrepareBlock)prepareBlock;
@end
#pragma mark -
typedef NS_ENUM(NSUInteger, SubactionMode) {
SubactionMode_Random = 0,
SubactionMode_Ordered,
};
@interface DebugUIMessagesGroupAction : DebugUIMessagesAction
@property (nonatomic, readonly) SubactionMode subactionMode;
@property (nonatomic, readonly, nullable) NSArray<DebugUIMessagesAction *> *subactions;
// Given a group of subactions, perform a single random subaction each time.
+ (DebugUIMessagesAction *)randomGroupActionWithLabel:(NSString *)label
subactions:(NSArray<DebugUIMessagesAction *> *)subactions;
// Given a group of subactions, perform the subactions in order.
//
// If prepareAndPerformNTimes: is called with count == subactions.count, all of the subactions
// are performed exactly once.
+ (DebugUIMessagesAction *)allGroupActionWithLabel:(NSString *)label
subactions:(NSArray<DebugUIMessagesAction *> *)subactions;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,288 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "DebugUIMessagesAction.h"
#import <SignalServiceKit/OWSPrimaryStorage.h>
NS_ASSUME_NONNULL_BEGIN
@class DebugUIMessagesSingleAction;
@interface DebugUIMessagesAction ()
@end
#pragma mark -
@interface DebugUIMessagesSingleAction ()
@property (nonatomic, nullable) ActionPrepareBlock prepareBlock;
// "Single" actions should have exactly one "staggered" or "unstaggered" action block.
@property (nonatomic, nullable) StaggeredActionBlock staggeredActionBlock;
@property (nonatomic, nullable) UnstaggeredActionBlock unstaggeredActionBlock;
@end
#pragma mark -
@implementation DebugUIMessagesAction
- (DebugUIMessagesSingleAction *)nextActionToPerform
{
return (DebugUIMessagesSingleAction *)self;
}
- (void)prepare:(ActionSuccessBlock)success failure:(ActionFailureBlock)failure
{
OWSAssert(success);
OWSAssert(failure);
OWS_ABSTRACT_METHOD();
success();
}
- (void)prepareAndPerformNTimes:(NSUInteger)count
{
DDLogInfo(@"%@ %@ prepareAndPerformNTimes: %zd", self.logTag, self.label, count);
[DDLog flushLog];
[self prepare:^{
[self performNTimes:count
success:^{
}
failure:^{
}];
}
failure:^{
}];
}
- (void)performNTimes:(NSUInteger)countParam success:(ActionSuccessBlock)success failure:(ActionFailureBlock)failure
{
OWSAssert(success);
OWSAssert(failure);
DDLogInfo(@"%@ %@ performNTimes: %zd", self.logTag, self.label, countParam);
[DDLog flushLog];
if (countParam < 1) {
success();
return;
}
__block NSUInteger count = countParam;
[OWSPrimaryStorage.sharedManager.newDatabaseConnection readWriteWithBlock:^(
YapDatabaseReadWriteTransaction *transaction) {
NSUInteger batchSize = 0;
while (count > 0) {
NSUInteger index = count;
DebugUIMessagesSingleAction *action = [self nextActionToPerform];
OWSAssert([action isKindOfClass:[DebugUIMessagesSingleAction class]]);
if (action.staggeredActionBlock) {
OWSAssert(!action.unstaggeredActionBlock);
action.staggeredActionBlock(index,
transaction,
^{
dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, (int64_t)1.f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
DDLogInfo(@"%@ %@ performNTimes success: %zd", self.logTag, self.label, count);
[self performNTimes:count - 1 success:success failure:failure];
});
},
failure);
break;
} else {
OWSAssert(action.unstaggeredActionBlock);
// TODO: We could check result for failure.
action.unstaggeredActionBlock(index, transaction);
const NSUInteger kMaxBatchSize = 2500;
batchSize++;
if (batchSize >= kMaxBatchSize) {
dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, (int64_t)1.f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
DDLogInfo(@"%@ %@ performNTimes success: %zd", self.logTag, self.label, count);
[self performNTimes:count - 1 success:success failure:failure];
});
break;
}
count--;
}
}
}];
}
@end
#pragma mark -
@implementation DebugUIMessagesSingleAction
+ (DebugUIMessagesAction *)actionWithLabel:(NSString *)label
staggeredActionBlock:(StaggeredActionBlock)staggeredActionBlock
{
OWSAssert(label.length > 0);
OWSAssert(staggeredActionBlock);
DebugUIMessagesSingleAction *instance = [DebugUIMessagesSingleAction new];
instance.label = label;
instance.staggeredActionBlock = staggeredActionBlock;
return instance;
}
+ (DebugUIMessagesAction *)actionWithLabel:(NSString *)label
unstaggeredActionBlock:(UnstaggeredActionBlock)unstaggeredActionBlock
{
OWSAssert(label.length > 0);
OWSAssert(unstaggeredActionBlock);
DebugUIMessagesSingleAction *instance = [DebugUIMessagesSingleAction new];
instance.label = label;
instance.unstaggeredActionBlock = unstaggeredActionBlock;
return instance;
}
+ (DebugUIMessagesAction *)actionWithLabel:(NSString *)label
staggeredActionBlock:(StaggeredActionBlock)staggeredActionBlock
prepareBlock:(ActionPrepareBlock)prepareBlock
{
OWSAssert(label.length > 0);
OWSAssert(staggeredActionBlock);
OWSAssert(prepareBlock);
DebugUIMessagesSingleAction *instance = [DebugUIMessagesSingleAction new];
instance.label = label;
instance.staggeredActionBlock = staggeredActionBlock;
instance.prepareBlock = prepareBlock;
return instance;
}
+ (DebugUIMessagesAction *)actionWithLabel:(NSString *)label
unstaggeredActionBlock:(UnstaggeredActionBlock)unstaggeredActionBlock
prepareBlock:(ActionPrepareBlock)prepareBlock
{
OWSAssert(label.length > 0);
OWSAssert(unstaggeredActionBlock);
OWSAssert(prepareBlock);
DebugUIMessagesSingleAction *instance = [DebugUIMessagesSingleAction new];
instance.label = label;
instance.unstaggeredActionBlock = unstaggeredActionBlock;
instance.prepareBlock = prepareBlock;
return instance;
}
- (void)prepare:(ActionSuccessBlock)success failure:(ActionFailureBlock)failure
{
OWSAssert(success);
OWSAssert(failure);
if (self.prepareBlock) {
self.prepareBlock(success, failure);
} else {
success();
}
}
@end
#pragma mark -
@interface DebugUIMessagesGroupAction ()
@property (nonatomic) SubactionMode subactionMode;
@property (nonatomic, nullable) NSArray<DebugUIMessagesAction *> *subactions;
@property (nonatomic) NSUInteger subactionIndex;
@end
#pragma mark -
@implementation DebugUIMessagesGroupAction
- (DebugUIMessagesSingleAction *)nextActionToPerform
{
OWSAssert(self.subactions.count > 0);
switch (self.subactionMode) {
case SubactionMode_Random: {
DebugUIMessagesAction *subaction = self.subactions[arc4random_uniform((uint32_t)self.subactions.count)];
OWSAssert(subaction);
return subaction.nextActionToPerform;
}
case SubactionMode_Ordered: {
DebugUIMessagesAction *subaction = self.subactions[self.subactionIndex];
OWSAssert(subaction);
self.subactionIndex = (self.subactionIndex + 1) % self.subactions.count;
return subaction.nextActionToPerform;
}
}
}
- (void)prepare:(ActionSuccessBlock)success failure:(ActionFailureBlock)failure
{
OWSAssert(success);
OWSAssert(failure);
[DebugUIMessagesGroupAction prepareSubactions:[self.subactions mutableCopy] success:success failure:failure];
}
+ (void)prepareSubactions:(NSMutableArray<DebugUIMessagesAction *> *)unpreparedSubactions
success:(ActionSuccessBlock)success
failure:(ActionFailureBlock)failure
{
OWSAssert(success);
OWSAssert(failure);
if (unpreparedSubactions.count < 1) {
return success();
}
DebugUIMessagesAction *nextAction = unpreparedSubactions.lastObject;
[unpreparedSubactions removeLastObject];
DDLogInfo(@"%@ preparing: %@", self.logTag, nextAction.label);
[DDLog flushLog];
[nextAction prepare:^{
[self prepareSubactions:unpreparedSubactions success:success failure:failure];
}
failure:^{
}];
}
+ (DebugUIMessagesAction *)randomGroupActionWithLabel:(NSString *)label
subactions:(NSArray<DebugUIMessagesAction *> *)subactions
{
OWSAssert(label.length > 0);
OWSAssert(subactions.count > 0);
DebugUIMessagesGroupAction *instance = [DebugUIMessagesGroupAction new];
instance.label = label;
instance.subactions = subactions;
instance.subactionMode = SubactionMode_Random;
return instance;
}
+ (DebugUIMessagesAction *)allGroupActionWithLabel:(NSString *)label
subactions:(NSArray<DebugUIMessagesAction *> *)subactions
{
OWSAssert(label.length > 0);
OWSAssert(subactions.count > 0);
DebugUIMessagesGroupAction *instance = [DebugUIMessagesGroupAction new];
instance.label = label;
instance.subactions = subactions;
instance.subactionMode = SubactionMode_Ordered;
return instance;
}
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,35 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "DebugUIMessagesUtils.h"
NS_ASSUME_NONNULL_BEGIN
@interface DebugUIMessagesAssetLoader : NSObject
@property (nonatomic) NSString *filename;
@property (nonatomic) NSString *mimeType;
@property (nonatomic) ActionPrepareBlock prepareBlock;
@property (nonatomic, nullable) NSString *filePath;
#pragma mark -
+ (instancetype)jpegInstance;
+ (instancetype)gifInstance;
+ (instancetype)mp3Instance;
+ (instancetype)mp4Instance;
+ (instancetype)portraitPngInstance;
+ (instancetype)landscapePngInstance;
+ (instancetype)largePngInstance;
+ (instancetype)tinyPdfInstance;
+ (instancetype)largePdfInstance;
+ (instancetype)missingPngInstance;
+ (instancetype)missingPdfInstance;
+ (instancetype)oversizeTextInstance;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,454 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "DebugUIMessagesAssetLoader.h"
#import <AFNetworking/AFHTTPSessionManager.h>
#import <AFNetworking/AFNetworking.h>
#import <Curve25519Kit/Randomness.h>
#import <SignalServiceKit/MIMETypeUtil.h>
#import <SignalServiceKit/OWSFileSystem.h>
NS_ASSUME_NONNULL_BEGIN
@implementation DebugUIMessagesAssetLoader
+ (DebugUIMessagesAssetLoader *)fakeAssetLoaderWithUrl:(NSString *)fileUrl mimeType:(NSString *)mimeType
{
OWSAssert(fileUrl.length > 0);
OWSAssert(mimeType.length > 0);
DebugUIMessagesAssetLoader *instance = [DebugUIMessagesAssetLoader new];
instance.mimeType = mimeType;
instance.filename = [NSURL URLWithString:fileUrl].lastPathComponent;
__weak DebugUIMessagesAssetLoader *weakSelf = instance;
instance.prepareBlock = ^(ActionSuccessBlock success, ActionFailureBlock failure) {
[weakSelf ensureURLAssetLoaded:fileUrl success:success failure:failure];
};
return instance;
}
- (void)ensureURLAssetLoaded:(NSString *)fileUrl success:(ActionSuccessBlock)success failure:(ActionFailureBlock)failure
{
OWSAssert(success);
OWSAssert(failure);
OWSAssert(self.filename.length > 0);
OWSAssert(self.mimeType.length > 0);
if (self.filePath) {
success();
return;
}
// Use a predictable file path so that we reuse the cache between app launches.
NSString *temporaryDirectory = NSTemporaryDirectory();
NSString *cacheDirectory = [temporaryDirectory stringByAppendingPathComponent:@"cached_random_files"];
[OWSFileSystem ensureDirectoryExists:cacheDirectory];
NSString *filePath = [cacheDirectory stringByAppendingPathComponent:self.filename];
if ([NSFileManager.defaultManager fileExistsAtPath:filePath]) {
self.filePath = filePath;
return success();
}
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:configuration];
sessionManager.responseSerializer = [AFHTTPResponseSerializer serializer];
OWSAssert(sessionManager.responseSerializer);
[sessionManager GET:fileUrl
parameters:nil
progress:nil
success:^(NSURLSessionDataTask *task, NSData *_Nullable responseObject) {
if ([responseObject writeToFile:filePath atomically:YES]) {
self.filePath = filePath;
OWSAssert([NSFileManager.defaultManager fileExistsAtPath:filePath]);
success();
} else {
OWSFail(@"Error write url response [%@]: %@", fileUrl, filePath);
failure();
}
}
failure:^(NSURLSessionDataTask *_Nullable task, NSError *requestError) {
OWSFail(@"Error downloading url[%@]: %@", fileUrl, requestError);
failure();
}];
}
#pragma mark -
+ (DebugUIMessagesAssetLoader *)fakePngAssetLoaderWithImageSize:(CGSize)imageSize
backgroundColor:(UIColor *)backgroundColor
textColor:(UIColor *)textColor
label:(NSString *)label
{
OWSAssert(imageSize.width > 0);
OWSAssert(imageSize.height > 0);
OWSAssert(backgroundColor);
OWSAssert(textColor);
OWSAssert(label.length > 0);
DebugUIMessagesAssetLoader *instance = [DebugUIMessagesAssetLoader new];
instance.mimeType = OWSMimeTypeImagePng;
instance.filename = @"image.png";
__weak DebugUIMessagesAssetLoader *weakSelf = instance;
instance.prepareBlock = ^(ActionSuccessBlock success, ActionFailureBlock failure) {
[weakSelf ensurePngAssetLoaded:imageSize
backgroundColor:backgroundColor
textColor:textColor
label:label
success:success
failure:failure];
};
return instance;
}
- (void)ensurePngAssetLoaded:(CGSize)imageSize
backgroundColor:(UIColor *)backgroundColor
textColor:(UIColor *)textColor
label:(NSString *)label
success:(ActionSuccessBlock)success
failure:(ActionFailureBlock)failure
{
OWSAssert(success);
OWSAssert(failure);
OWSAssert(self.filename.length > 0);
OWSAssert(self.mimeType.length > 0);
OWSAssert(imageSize.width > 0 && imageSize.height > 0);
OWSAssert(backgroundColor);
OWSAssert(textColor);
OWSAssert(label.length > 0);
if (self.filePath) {
success();
return;
}
NSString *filePath = [OWSFileSystem temporaryFilePathWithFileExtension:@"png"];
UIImage *image =
[self createRandomPngWithSize:imageSize backgroundColor:backgroundColor textColor:textColor label:label];
NSData *pngData = UIImagePNGRepresentation(image);
[pngData writeToFile:filePath atomically:YES];
self.filePath = filePath;
OWSAssert([NSFileManager.defaultManager fileExistsAtPath:filePath]);
success();
}
- (nullable UIImage *)createRandomPngWithSize:(CGSize)imageSize
backgroundColor:(UIColor *)backgroundColor
textColor:(UIColor *)textColor
label:(NSString *)label
{
OWSAssert(imageSize.width > 0 && imageSize.height > 0);
OWSAssert(backgroundColor);
OWSAssert(textColor);
OWSAssert(label.length > 0);
CGRect frame = CGRectZero;
frame.size = imageSize;
CGFloat smallDimension = MIN(imageSize.width, imageSize.height);
UIFont *font = [UIFont boldSystemFontOfSize:smallDimension * 0.5f];
NSDictionary *textAttributes = @{ NSFontAttributeName : font, NSForegroundColorAttributeName : textColor };
CGRect textFrame =
[label boundingRectWithSize:frame.size
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
attributes:textAttributes
context:nil];
UIGraphicsBeginImageContextWithOptions(frame.size, NO, [UIScreen mainScreen].scale);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, backgroundColor.CGColor);
CGContextFillRect(context, frame);
[label drawAtPoint:CGPointMake(CGRectGetMidX(frame) - CGRectGetMidX(textFrame),
CGRectGetMidY(frame) - CGRectGetMidY(textFrame))
withAttributes:textAttributes];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
#pragma mark -
+ (DebugUIMessagesAssetLoader *)fakeRandomAssetLoaderWithLength:(NSUInteger)dataLength mimeType:(NSString *)mimeType
{
OWSAssert(dataLength > 0);
OWSAssert(mimeType.length > 0);
DebugUIMessagesAssetLoader *instance = [DebugUIMessagesAssetLoader new];
instance.mimeType = mimeType;
NSString *fileExtension = [MIMETypeUtil fileExtensionForMIMEType:mimeType];
OWSAssert(fileExtension.length > 0);
instance.filename = [@"attachment" stringByAppendingPathExtension:fileExtension];
__weak DebugUIMessagesAssetLoader *weakSelf = instance;
instance.prepareBlock = ^(ActionSuccessBlock success, ActionFailureBlock failure) {
[weakSelf ensureRandomAssetLoaded:dataLength success:success failure:failure];
};
return instance;
}
- (void)ensureRandomAssetLoaded:(NSUInteger)dataLength
success:(ActionSuccessBlock)success
failure:(ActionFailureBlock)failure
{
OWSAssert(dataLength > 0);
OWSAssert(success);
OWSAssert(failure);
OWSAssert(self.filename.length > 0);
OWSAssert(self.mimeType.length > 0);
if (self.filePath) {
success();
return;
}
NSString *fileExtension = [MIMETypeUtil fileExtensionForMIMEType:self.mimeType];
OWSAssert(fileExtension.length > 0);
NSData *data = [Randomness generateRandomBytes:(int)dataLength];
OWSAssert(data);
NSString *filePath = [OWSFileSystem temporaryFilePathWithFileExtension:fileExtension];
BOOL didWrite = [data writeToFile:filePath atomically:YES];
OWSAssert(didWrite);
self.filePath = filePath;
OWSAssert([NSFileManager.defaultManager fileExistsAtPath:filePath]);
success();
}
#pragma mark -
+ (DebugUIMessagesAssetLoader *)fakeMissingAssetLoaderWithMimeType:(NSString *)mimeType
{
OWSAssert(mimeType.length > 0);
DebugUIMessagesAssetLoader *instance = [DebugUIMessagesAssetLoader new];
instance.mimeType = mimeType;
NSString *fileExtension = [MIMETypeUtil fileExtensionForMIMEType:mimeType];
OWSAssert(fileExtension.length > 0);
instance.filename = [@"attachment" stringByAppendingPathExtension:fileExtension];
__weak DebugUIMessagesAssetLoader *weakSelf = instance;
instance.prepareBlock = ^(ActionSuccessBlock success, ActionFailureBlock failure) {
[weakSelf ensureMissingAssetLoaded:success failure:failure];
};
return instance;
}
- (void)ensureMissingAssetLoaded:(ActionSuccessBlock)success failure:(ActionFailureBlock)failure
{
OWSAssert(success);
OWSAssert(failure);
OWSAssert(self.filename.length > 0);
OWSAssert(self.mimeType.length > 0);
if (self.filePath) {
success();
return;
}
NSString *fileExtension = [MIMETypeUtil fileExtensionForMIMEType:self.mimeType];
OWSAssert(fileExtension.length > 0);
NSString *filePath = [OWSFileSystem temporaryFilePathWithFileExtension:fileExtension];
BOOL didCreate = [NSFileManager.defaultManager createFileAtPath:filePath contents:nil attributes:nil];
OWSAssert(didCreate);
self.filePath = filePath;
OWSAssert([NSFileManager.defaultManager fileExistsAtPath:filePath]);
success();
}
#pragma mark -
+ (DebugUIMessagesAssetLoader *)fakeOversizeTextAssetLoader
{
DebugUIMessagesAssetLoader *instance = [DebugUIMessagesAssetLoader new];
instance.mimeType = OWSMimeTypeOversizeTextMessage;
instance.filename = @"attachment.txt";
__weak DebugUIMessagesAssetLoader *weakSelf = instance;
instance.prepareBlock = ^(ActionSuccessBlock success, ActionFailureBlock failure) {
[weakSelf ensureOversizeTextAssetLoaded:success failure:failure];
};
return instance;
}
- (void)ensureOversizeTextAssetLoaded:(ActionSuccessBlock)success failure:(ActionFailureBlock)failure
{
OWSAssert(success);
OWSAssert(failure);
OWSAssert(self.filename.length > 0);
OWSAssert(self.mimeType.length > 0);
if (self.filePath) {
success();
return;
}
NSMutableString *message = [NSMutableString new];
for (NSUInteger i = 0; i < 32; i++) {
[message appendString:@"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse rutrum, nulla "
@"vitae pretium hendrerit, tellus turpis pharetra libero, vitae sodales tortor ante vel "
@"sem. Fusce sed nisl a lorem gravida tincidunt. Suspendisse efficitur non quam ac "
@"sodales. Aenean ut velit maximus, posuere sem a, accumsan nunc. Donec ullamcorper "
@"turpis lorem. Quisque dignissim purus eu placerat ultricies. Proin at urna eget mi "
@"semper congue. Aenean non elementum ex. Praesent pharetra quam at sem vestibulum, "
@"vestibulum ornare dolor elementum. Vestibulum massa tortor, scelerisque sit amet "
@"pulvinar a, rhoncus vitae nisl. Sed mi nunc, tempus at varius in, malesuada vitae "
@"dui. Vivamus efficitur pulvinar erat vitae congue. Proin vehicula turpis non felis "
@"congue facilisis. Nullam aliquet dapibus ligula ac mollis. Etiam sit amet posuere "
@"lorem, in rhoncus nisi.\n\n"];
}
NSString *fileExtension = @"txt";
NSString *filePath = [OWSFileSystem temporaryFilePathWithFileExtension:fileExtension];
NSData *data = [message dataUsingEncoding:NSUTF8StringEncoding];
OWSAssert(data);
BOOL didWrite = [data writeToFile:filePath atomically:YES];
OWSAssert(didWrite);
self.filePath = filePath;
OWSAssert([NSFileManager.defaultManager fileExistsAtPath:filePath]);
success();
}
#pragma mark -
+ (instancetype)jpegInstance
{
static DebugUIMessagesAssetLoader *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [DebugUIMessagesAssetLoader
fakeAssetLoaderWithUrl:@"https://s3.amazonaws.com/ows-data/example_attachment_media/random-jpg.JPG"
mimeType:@"image/jpeg"];
});
return instance;
}
+ (instancetype)gifInstance
{
static DebugUIMessagesAssetLoader *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [DebugUIMessagesAssetLoader
fakeAssetLoaderWithUrl:@"https://s3.amazonaws.com/ows-data/example_attachment_media/random-gif.gif"
mimeType:@"image/gif"];
});
return instance;
}
+ (instancetype)mp3Instance
{
static DebugUIMessagesAssetLoader *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [DebugUIMessagesAssetLoader
fakeAssetLoaderWithUrl:@"https://s3.amazonaws.com/ows-data/example_attachment_media/random-mp3.mp3"
mimeType:@"audio/mpeg"];
});
return instance;
}
+ (instancetype)mp4Instance
{
static DebugUIMessagesAssetLoader *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [DebugUIMessagesAssetLoader
fakeAssetLoaderWithUrl:@"https://s3.amazonaws.com/ows-data/example_attachment_media/random-mp4.mp4"
mimeType:@"video/mp4"];
});
return instance;
}
+ (instancetype)portraitPngInstance
{
static DebugUIMessagesAssetLoader *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [DebugUIMessagesAssetLoader fakePngAssetLoaderWithImageSize:CGSizeMake(10, 100)
backgroundColor:[UIColor blueColor]
textColor:[UIColor whiteColor]
label:@"P"];
});
return instance;
}
+ (instancetype)landscapePngInstance
{
static DebugUIMessagesAssetLoader *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [DebugUIMessagesAssetLoader fakePngAssetLoaderWithImageSize:CGSizeMake(100, 10)
backgroundColor:[UIColor greenColor]
textColor:[UIColor whiteColor]
label:@"L"];
});
return instance;
}
+ (instancetype)largePngInstance
{
static DebugUIMessagesAssetLoader *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [DebugUIMessagesAssetLoader fakePngAssetLoaderWithImageSize:CGSizeMake(4000, 4000)
backgroundColor:[UIColor redColor]
textColor:[UIColor whiteColor]
label:@"B"];
});
return instance;
}
+ (instancetype)tinyPdfInstance
{
static DebugUIMessagesAssetLoader *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [DebugUIMessagesAssetLoader fakeRandomAssetLoaderWithLength:256 mimeType:@"application/pdf"];
});
return instance;
}
+ (instancetype)largePdfInstance
{
static DebugUIMessagesAssetLoader *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [DebugUIMessagesAssetLoader fakeRandomAssetLoaderWithLength:256 mimeType:@"application/pdf"];
});
return instance;
}
+ (instancetype)missingPngInstance
{
static DebugUIMessagesAssetLoader *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [DebugUIMessagesAssetLoader fakeMissingAssetLoaderWithMimeType:OWSMimeTypeImagePng];
});
return instance;
}
+ (instancetype)missingPdfInstance
{
static DebugUIMessagesAssetLoader *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [DebugUIMessagesAssetLoader fakeMissingAssetLoaderWithMimeType:@"application/pdf"];
});
return instance;
}
+ (instancetype)oversizeTextInstance
{
static DebugUIMessagesAssetLoader *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [DebugUIMessagesAssetLoader fakeOversizeTextAssetLoader];
});
return instance;
}
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,18 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
NS_ASSUME_NONNULL_BEGIN
@class YapDatabaseReadWriteTransaction;
typedef void (^ActionSuccessBlock)(void);
typedef void (^ActionFailureBlock)(void);
typedef void (^ActionPrepareBlock)(ActionSuccessBlock success, ActionFailureBlock failure);
typedef void (^StaggeredActionBlock)(NSUInteger index,
YapDatabaseReadWriteTransaction *transaction,
ActionSuccessBlock success,
ActionFailureBlock failure);
typedef void (^UnstaggeredActionBlock)(NSUInteger index, YapDatabaseReadWriteTransaction *transaction);
NS_ASSUME_NONNULL_END