diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 62f20f007..271f939a4 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -204,8 +204,8 @@ 45194F951FD7216600333B2C /* TSUnreadIndicatorInteraction.m in Sources */ = {isa = PBXBuildFile; fileRef = 34C42D651F4734ED0072EC04 /* TSUnreadIndicatorInteraction.m */; }; 45194F961FD7226300333B2C /* SelectThreadViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3400C7941EAF99F4008A8584 /* SelectThreadViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 451A13B11E13DED2000A50FD /* CallNotificationsAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451A13B01E13DED2000A50FD /* CallNotificationsAdapter.swift */; }; - 451F8A311FD70DE9005CB9DA /* SendExternalFileViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3400C7911EAF89CD008A8584 /* SendExternalFileViewController.m */; }; - 451F8A321FD70DFA005CB9DA /* SendExternalFileViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3400C7901EAF89CD008A8584 /* SendExternalFileViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 451F8A311FD70DE9005CB9DA /* SharingThreadPickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3400C7911EAF89CD008A8584 /* SharingThreadPickerViewController.m */; }; + 451F8A321FD70DFA005CB9DA /* SharingThreadPickerViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3400C7901EAF89CD008A8584 /* SharingThreadPickerViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 451F8A331FD71083005CB9DA /* SelectThreadViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3400C7951EAF99F4008A8584 /* SelectThreadViewController.m */; }; 451F8A341FD710C3005CB9DA /* ConversationSearcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451777C71FD61554001225FF /* ConversationSearcher.swift */; }; 451F8A351FD710DE005CB9DA /* Searcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45360B8C1F9521F800FA666C /* Searcher.swift */; }; @@ -281,6 +281,7 @@ 45A6DAD61EBBF85500893231 /* ReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45A6DAD51EBBF85500893231 /* ReminderView.swift */; }; 45AE48511E0732D6004D96C2 /* TurnServerInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45AE48501E0732D6004D96C2 /* TurnServerInfo.swift */; }; 45BB93381E688E14001E3939 /* UIDevice+featureSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45BB93371E688E14001E3939 /* UIDevice+featureSupport.swift */; }; + 45BC829D1FD9C4B400011CF3 /* ShareViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45BC829C1FD9C4B400011CF3 /* ShareViewDelegate.swift */; }; 45BD60821DE9547E00A8F436 /* Contacts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 45BD60811DE9547E00A8F436 /* Contacts.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 45C0DC1B1E68FE9000E04C47 /* UIApplication+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45C0DC1A1E68FE9000E04C47 /* UIApplication+OWS.swift */; }; 45C0DC1E1E69011F00E04C47 /* UIStoryboard+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45C0DC1D1E69011F00E04C47 /* UIStoryboard+OWS.swift */; }; @@ -460,8 +461,8 @@ 1C93CF3971B64E8B6C1F9AC1 /* Pods-SignalShareExtension.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalShareExtension.test.xcconfig"; path = "Pods/Target Support Files/Pods-SignalShareExtension/Pods-SignalShareExtension.test.xcconfig"; sourceTree = ""; }; 1CE3CD5C23334683BDD3D78C /* Pods-Signal.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Signal.test.xcconfig"; path = "Pods/Target Support Files/Pods-Signal/Pods-Signal.test.xcconfig"; sourceTree = ""; }; 264242150E87D10A357DB07B /* Pods_SignalMessaging.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SignalMessaging.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 3400C7901EAF89CD008A8584 /* SendExternalFileViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SendExternalFileViewController.h; sourceTree = ""; }; - 3400C7911EAF89CD008A8584 /* SendExternalFileViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SendExternalFileViewController.m; sourceTree = ""; }; + 3400C7901EAF89CD008A8584 /* SharingThreadPickerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SharingThreadPickerViewController.h; sourceTree = ""; }; + 3400C7911EAF89CD008A8584 /* SharingThreadPickerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SharingThreadPickerViewController.m; sourceTree = ""; }; 3400C7941EAF99F4008A8584 /* SelectThreadViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SelectThreadViewController.h; sourceTree = ""; }; 3400C7951EAF99F4008A8584 /* SelectThreadViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SelectThreadViewController.m; sourceTree = ""; }; 3400C7971EAFB772008A8584 /* ThreadViewHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadViewHelper.h; sourceTree = ""; }; @@ -812,6 +813,7 @@ 45AE48501E0732D6004D96C2 /* TurnServerInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TurnServerInfo.swift; sourceTree = ""; }; 45B201741DAECBFD00C461E0 /* Signal-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Signal-Bridging-Header.h"; sourceTree = ""; }; 45BB93371E688E14001E3939 /* UIDevice+featureSupport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIDevice+featureSupport.swift"; sourceTree = ""; }; + 45BC829C1FD9C4B400011CF3 /* ShareViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewDelegate.swift; sourceTree = ""; }; 45BD60811DE9547E00A8F436 /* Contacts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Contacts.framework; path = System/Library/Frameworks/Contacts.framework; sourceTree = SDKROOT; }; 45C0DC1A1E68FE9000E04C47 /* UIApplication+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIApplication+OWS.swift"; sourceTree = ""; }; 45C0DC1D1E69011F00E04C47 /* UIStoryboard+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIStoryboard+OWS.swift"; sourceTree = ""; }; @@ -1542,12 +1544,13 @@ 34B3F8471E8DF1700035BE1A /* FullImageViewController.h */, 34B3F8481E8DF1700035BE1A /* FullImageViewController.m */, 45E5471F1FD755E700DFC09E /* AttachmentApprovalViewController.swift */, - 3400C7901EAF89CD008A8584 /* SendExternalFileViewController.h */, - 3400C7911EAF89CD008A8584 /* SendExternalFileViewController.m */, + 3400C7901EAF89CD008A8584 /* SharingThreadPickerViewController.h */, + 3400C7911EAF89CD008A8584 /* SharingThreadPickerViewController.m */, 34533F161EA8D2070006114F /* OWSAudioAttachmentPlayer.h */, 34533F171EA8D2070006114F /* OWSAudioAttachmentPlayer.m */, 34D913491F62D4A500722898 /* SignalAttachment.swift */, 34CA1C281F7164F700E51C51 /* MediaMessageView.swift */, + 45BC829C1FD9C4B400011CF3 /* ShareViewDelegate.swift */, ); path = attachments; sourceTree = ""; @@ -2022,7 +2025,7 @@ 451F8A3C1FD71392005CB9DA /* UIUtil.h in Headers */, 346129D61FD20ADC00532771 /* UIViewController+OWS.h in Headers */, 451F8A401FD7145D005CB9DA /* OWSTableViewController.h in Headers */, - 451F8A321FD70DFA005CB9DA /* SendExternalFileViewController.h in Headers */, + 451F8A321FD70DFA005CB9DA /* SharingThreadPickerViewController.h in Headers */, 3461296F1FD1D74C00532771 /* Release.h in Headers */, 34612A061FD7238600532771 /* OWSContactsSyncing.h in Headers */, 34480B571FD0A7A400BC14EF /* OWSScrubbingLogFormatter.h in Headers */, @@ -2720,6 +2723,7 @@ 451F8A331FD71083005CB9DA /* SelectThreadViewController.m in Sources */, 454A965A1FD6017E008D2A0E /* SignalAttachment.swift in Sources */, 454A965B1FD601BF008D2A0E /* MediaMessageView.swift in Sources */, + 45BC829D1FD9C4B400011CF3 /* ShareViewDelegate.swift in Sources */, 3461295B1FD1D74C00532771 /* Environment.m in Sources */, 346129D51FD20ADC00532771 /* UIViewController+OWS.m in Sources */, 451F8A431FD714FE005CB9DA /* AvatarImageView.swift in Sources */, @@ -2745,7 +2749,7 @@ 3461293C1FD1D46A00532771 /* OWSMath.m in Sources */, 451F8A391FD711D6005CB9DA /* ContactsViewHelper.m in Sources */, 346129AF1FD1F5D900532771 /* SystemContactsFetcher.swift in Sources */, - 451F8A311FD70DE9005CB9DA /* SendExternalFileViewController.m in Sources */, + 451F8A311FD70DE9005CB9DA /* SharingThreadPickerViewController.m in Sources */, 451F8A411FD714B8005CB9DA /* ContactTableViewCell.m in Sources */, 346129C81FD2072E00532771 /* NSAttributedString+OWS.m in Sources */, ); diff --git a/Signal/Signal-Info.plist b/Signal/Signal-Info.plist index 46544c8ce..1266e64c8 100644 --- a/Signal/Signal-Info.plist +++ b/Signal/Signal-Info.plist @@ -15,12 +15,6 @@ Signal LSHandlerRank Alternate - LSItemContentTypes - - public.archive - public.content - public.data - CFBundleExecutable diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index 665fa7048..4bd30344c 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -18,7 +18,6 @@ #import "PushManager.h" #import "RegistrationViewController.h" #import "Release.h" -#import "SendExternalFileViewController.h" #import "Signal-Swift.h" #import "SignalApp.h" #import "SignalsNavigationController.h" @@ -328,9 +327,10 @@ static NSString *const kURLHostVerifyPrefix = @"verify"; } - (BOOL)application:(UIApplication *)application - openURL:(NSURL *)url - sourceApplication:(NSString *)sourceApplication - annotation:(id)annotation { + openURL:(NSURL *)url + sourceApplication:(NSString *)sourceApplication + annotation:(id)annotation +{ if ([url.scheme isEqualToString:kURLSchemeSGNLKey]) { if ([url.host hasPrefix:kURLHostVerifyPrefix] && ![TSAccountManager isRegistered]) { id signupController = SignalApp.sharedApp.signUpFlowNavigationController; @@ -341,160 +341,21 @@ static NSString *const kURLHostVerifyPrefix = @"verify"; CodeVerificationViewController *cvvc = (CodeVerificationViewController *)controller; NSString *verificationCode = [url.path substringFromIndex:1]; [cvvc setVerificationCodeAndTryToVerify:verificationCode]; + return YES; } else { DDLogWarn(@"Not the verification view controller we expected. Got %@ instead", NSStringFromClass(controller.class)); } } } else { - DDLogWarn(@"Application opened with an unknown URL action: %@", url.host); + OWSFail(@"Application opened with an unknown URL action: %@", url.host); } - } else if ([url.scheme.lowercaseString isEqualToString:@"file"]) { - - if (SignalApp.sharedApp.callService.call != nil) { - DDLogWarn(@"%@ ignoring 'open with Signal' due to ongoing WebRTC call.", self.logTag); - return NO; - } - - NSString *filename = url.lastPathComponent; - if ([filename stringByDeletingPathExtension].length < 1) { - DDLogError(@"Application opened with URL invalid filename: %@", url); - [OWSAlerts showAlertWithTitle: - NSLocalizedString(@"EXPORT_WITH_SIGNAL_ERROR_TITLE", - @"Title for the alert indicating the 'export with signal' attachment had an error.") - message:NSLocalizedString(@"EXPORT_WITH_SIGNAL_ERROR_MESSAGE_INVALID_FILENAME", - @"Message for the alert indicating the 'export with signal' file had an " - @"invalid filename.")]; - return NO; - } - NSString *fileExtension = [filename pathExtension]; - if (fileExtension.length < 1) { - DDLogError(@"Application opened with URL missing file extension: %@", url); - [OWSAlerts showAlertWithTitle: - NSLocalizedString(@"EXPORT_WITH_SIGNAL_ERROR_TITLE", - @"Title for the alert indicating the 'export with signal' attachment had an error.") - message:NSLocalizedString(@"EXPORT_WITH_SIGNAL_ERROR_MESSAGE_UNKNOWN_TYPE", - @"Message for the alert indicating the 'export with signal' file had " - @"unknown type.")]; - return NO; - } - - - NSString *utiType; - NSError *typeError; - [url getResourceValue:&utiType forKey:NSURLTypeIdentifierKey error:&typeError]; - if (typeError) { - OWSFail(@"%@ Determining type of picked document at url: %@ failed with error: %@", - self.logTag, - url, - typeError); - return NO; - } - if (!utiType) { - OWSFail(@"%@ falling back to default filetype for picked document at url: %@", self.logTag, url); - utiType = (__bridge NSString *)kUTTypeData; - return NO; - } - - NSNumber *isDirectory; - NSError *isDirectoryError; - [url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:&isDirectoryError]; - if (isDirectoryError) { - OWSFail(@"%@ Determining if picked document at url: %@ was a directory failed with error: %@", - self.logTag, - url, - isDirectoryError); - return NO; - } else if ([isDirectory boolValue]) { - DDLogInfo(@"%@ User picked directory at url: %@", self.logTag, url); - DDLogError(@"Application opened with URL of unknown UTI type: %@", url); - [OWSAlerts - showAlertWithTitle: - NSLocalizedString(@"ATTACHMENT_PICKER_DOCUMENTS_PICKED_DIRECTORY_FAILED_ALERT_TITLE", - @"Alert title when picking a document fails because user picked a directory/bundle") - message: - NSLocalizedString(@"ATTACHMENT_PICKER_DOCUMENTS_PICKED_DIRECTORY_FAILED_ALERT_BODY", - @"Alert body when picking a document fails because user picked a directory/bundle")]; - return NO; - } - - DataSource *_Nullable dataSource = [DataSourcePath dataSourceWithURL:url]; - if (!dataSource) { - DDLogError(@"Application opened with URL with unloadable content: %@", url); - [OWSAlerts showAlertWithTitle: - NSLocalizedString(@"EXPORT_WITH_SIGNAL_ERROR_TITLE", - @"Title for the alert indicating the 'export with signal' attachment had an error.") - message:NSLocalizedString(@"EXPORT_WITH_SIGNAL_ERROR_MESSAGE_MISSING_DATA", - @"Message for the alert indicating the 'export with signal' data " - @"couldn't be loaded.")]; - return NO; - } - [dataSource setSourceFilename:filename]; - - SignalAttachment *attachment = [SignalAttachment attachmentWithDataSource:dataSource dataUTI:utiType]; - if (!attachment) { - DDLogError(@"Application opened with URL with invalid content: %@", url); - [OWSAlerts showAlertWithTitle: - NSLocalizedString(@"EXPORT_WITH_SIGNAL_ERROR_TITLE", - @"Title for the alert indicating the 'export with signal' attachment had an error.") - message:NSLocalizedString(@"EXPORT_WITH_SIGNAL_ERROR_MESSAGE_MISSING_ATTACHMENT", - @"Message for the alert indicating the 'export with signal' attachment " - @"couldn't be loaded.")]; - return NO; - } - if ([attachment hasError]) { - DDLogError(@"Application opened with URL with content error: %@ %@", url, [attachment errorName]); - [OWSAlerts showAlertWithTitle: - NSLocalizedString(@"EXPORT_WITH_SIGNAL_ERROR_TITLE", - @"Title for the alert indicating the 'export with signal' attachment had an error.") - message:[attachment errorName]]; - return NO; - } - DDLogInfo(@"Application opened with URL: %@", url); - - if ([TSAccountManager isRegistered]) { - dispatch_async(dispatch_get_main_queue(), ^{ - // Wait up to N seconds for database view registrations to - // complete. - [self showImportUIForAttachment:attachment remainingRetries:5]; - }); - } - - return YES; } else { - DDLogWarn(@"Application opened with an unknown URL scheme: %@", url.scheme); + OWSFail(@"Application opened with an unknown URL scheme: %@", url.scheme); } return NO; } -- (void)showImportUIForAttachment:(SignalAttachment *)attachment remainingRetries:(int)remainingRetries -{ - OWSAssert([NSThread isMainThread]); - OWSAssert(attachment); - OWSAssert(remainingRetries > 0); - - if ([TSDatabaseView hasPendingViewRegistrations]) { - if (remainingRetries < 1) { - DDLogInfo(@"Ignoring 'Import with Signal...' due to pending view registrations."); - } else { - DDLogInfo(@"Delaying 'Import with Signal...' due to pending view registrations."); - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)1.f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - if (![TSDatabaseView hasPendingViewRegistrations]) { - [self showImportUIForAttachment:attachment remainingRetries:remainingRetries - 1]; - } - }); - } - return; - } - - SendExternalFileViewController *viewController = [SendExternalFileViewController new]; - viewController.attachment = attachment; - UINavigationController *navigationController = - [[UINavigationController alloc] initWithRootViewController:viewController]; - [SignalApp.sharedApp.homeViewController presentTopLevelModalViewController:navigationController - animateDismissal:NO - animatePresentation:YES]; -} - (void)applicationDidBecomeActive:(UIApplication *)application { DDLogWarn(@"%@ applicationDidBecomeActive.", self.logTag); diff --git a/SignalMessaging/SignalMessaging.h b/SignalMessaging/SignalMessaging.h index 80b4d85d3..9d9900e8d 100644 --- a/SignalMessaging/SignalMessaging.h +++ b/SignalMessaging/SignalMessaging.h @@ -24,7 +24,7 @@ FOUNDATION_EXPORT const unsigned char SignalMessagingVersionString[]; #import #import #import -#import +#import #import #import #import diff --git a/SignalMessaging/attachments/AttachmentApprovalViewController.swift b/SignalMessaging/attachments/AttachmentApprovalViewController.swift index 104798edf..43321c737 100644 --- a/SignalMessaging/attachments/AttachmentApprovalViewController.swift +++ b/SignalMessaging/attachments/AttachmentApprovalViewController.swift @@ -166,6 +166,15 @@ public class AttachmentApprovalViewController: OWSViewController { } func sendPressed(sender: UIButton) { + + // FIXME + // this is just a temporary hack to provide some UI + // until we have a proper progress indicator + let activityIndicatorView = UIActivityIndicatorView() + view.addSubview(activityIndicatorView) + activityIndicatorView.autoCenterInSuperview() + activityIndicatorView.startAnimating() + self.delegate?.didApproveAttachment() } } diff --git a/SignalMessaging/attachments/SendExternalFileViewController.m b/SignalMessaging/attachments/SendExternalFileViewController.m deleted file mode 100644 index afa2ab702..000000000 --- a/SignalMessaging/attachments/SendExternalFileViewController.m +++ /dev/null @@ -1,212 +0,0 @@ -// -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. -// - -#import "SendExternalFileViewController.h" -#import "Environment.h" -#import "NSString+OWS.h" -#import "SignalApp.h" -#import "ThreadUtil.h" -#import "UIColor+OWS.h" -#import "UIFont+OWS.h" -#import "UIView+OWS.h" -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface SendExternalFileViewController () - -@property (nonatomic, readonly) OWSContactsManager *contactsManager; -@property (nonatomic, readonly) OWSMessageSender *messageSender; -@property (nonatomic) TSThread *thread; - -@end - -#pragma mark - - -@implementation SendExternalFileViewController - -- (instancetype)init -{ - if (self = [super init]) { - self.delegate = self; - } - return self; -} - -- (void)loadView -{ - [super loadView]; - - _contactsManager = [Environment current].contactsManager; - _messageSender = [Environment current].messageSender; - - self.title = NSLocalizedString(@"SEND_EXTERNAL_FILE_VIEW_TITLE", @"Title for the 'send external file' view."); -} - -- (BOOL)canSelectBlockedContact -{ - return NO; -} - -- (nullable UIView *)createHeaderWithSearchBar:(UISearchBar *)searchBar -{ - OWSAssert(searchBar) - - const CGFloat imageSize - = ScaleFromIPhone5To7Plus(40, 50); - const CGFloat imageLabelSpacing = ScaleFromIPhone5To7Plus(5, 8); - const CGFloat titleVSpacing = ScaleFromIPhone5To7Plus(10, 15); - const CGFloat contentVMargin = 20; - - UIView *header = [UIView new]; - header.backgroundColor = [UIColor whiteColor]; - - UIView *titleLabel = [self createTitleLabel]; - [titleLabel sizeToFit]; - [header addSubview:titleLabel]; - [titleLabel autoHCenterInSuperview]; - [titleLabel autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:contentVMargin]; - - UIView *fileView = [UIView new]; - [header addSubview:fileView]; - [fileView autoHCenterInSuperview]; - [fileView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:titleLabel withOffset:titleVSpacing]; - - UIImage *image = [UIImage imageNamed:@"file-thin-black-filled-large"]; - OWSAssert(image); - UIImageView *imageView = [[UIImageView alloc] initWithImage:image]; - imageView.layer.minificationFilter = kCAFilterTrilinear; - imageView.layer.magnificationFilter = kCAFilterTrilinear; - imageView.layer.shadowColor = [UIColor blackColor].CGColor; - imageView.layer.shadowRadius = 2.f; - imageView.layer.shadowOpacity = 0.2f; - imageView.layer.shadowOffset = CGSizeMake(0.75f, 0.75f); - [fileView addSubview:imageView]; - [imageView autoSetDimension:ALDimensionWidth toSize:imageSize]; - [imageView autoSetDimension:ALDimensionHeight toSize:imageSize]; - [imageView autoPinLeadingToSuperview]; - [imageView autoPinEdgeToSuperviewEdge:ALEdgeTop]; - [imageView autoPinEdgeToSuperviewEdge:ALEdgeBottom]; - - UIView *fileNameLabel = [self createFileNameLabel]; - [fileView addSubview:fileNameLabel]; - [fileNameLabel autoAlignAxis:ALAxisHorizontal toSameAxisOfView:imageView]; - [fileNameLabel autoPinLeadingToTrailingOfView:imageView margin:imageLabelSpacing]; - [fileNameLabel autoPinTrailingToSuperview]; - - [header addSubview:searchBar]; - [searchBar autoPinWidthToSuperview]; - [searchBar autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:fileView withOffset:contentVMargin]; - [searchBar autoPinEdgeToSuperviewEdge:ALEdgeBottom]; - - // UITableViewController.tableHeaderView must have its height set. - header.frame = CGRectMake(0, - 0, - 0, - (contentVMargin * 2 + titleLabel.frame.size.height + titleVSpacing + imageSize + searchBar.frame.size.height)); - - return header; -} - -- (NSString *)formattedFileName -{ - // AppDelegate already verifies that this attachment has a valid filename. - // - // TODO: If we reuse this VC, for example to offer a "forward attachment to other thread", - // feature, this assumption would no longer apply. - OWSAssert(self.attachment); - NSString *filename = [self.attachment.sourceFilename ows_stripped]; - OWSAssert(filename.length > 0); - const NSUInteger kMaxFilenameLength = 20; - if (filename.length > kMaxFilenameLength) { - // Truncate the filename if necessary. - // - // TODO: Use l10n-safe truncation. - filename = [[[filename substringToIndex:kMaxFilenameLength / 2] stringByAppendingString:@"…"] - stringByAppendingString:[filename substringFromIndex:filename.length - kMaxFilenameLength / 2]]; - } - return filename; -} - -- (UIView *)createFileNameLabel -{ - UILabel *label = [UILabel new]; - label.text = [self formattedFileName]; - label.textColor = [UIColor ows_materialBlueColor]; - label.font = [UIFont ows_regularFontWithSize:ScaleFromIPhone5To7Plus(16.f, 20.f)]; - return label; -} - - -- (UIView *)createTitleLabel -{ - UILabel *label = [UILabel new]; - label.text - = NSLocalizedString(@"SEND_EXTERNAL_FILE_HEADER_TITLE", @"Header title for the 'send external file' view."); - label.textColor = [UIColor blackColor]; - label.font = [UIFont ows_mediumFontWithSize:ScaleFromIPhone5To7Plus(18.f, 20.f)]; - return label; -} - -#pragma mark - SelectThreadViewControllerDelegate - -- (void)threadWasSelected:(TSThread *)thread -{ - OWSAssert(self.attachment); - OWSAssert(thread); - self.thread = thread; - - __weak typeof(self) weakSelf = self; - - // FIXME SHARINGEXTENSION - // Handling safety number changes brings in a lot of machinery. - // How do we want to handle this? - // e.g. fingerprint scanning, etc. in the SAE or just redirect the user to the main app? - // BOOL didShowSNAlert = - // [SafetyNumberConfirmationAlert presentAlertIfNecessaryWithRecipientIds:thread.recipientIdentifiers - // confirmationText:[SafetyNumberStrings - // confirmSendButton] - // contactsManager:self.contactsManager - // completion:^(BOOL didConfirm) { - // if (didConfirm) { - // [weakSelf threadWasSelected:thread]; - // } - // }]; - // if (didShowSNAlert) { - // return; - // } - - AttachmentApprovalViewController *approvalVC = - [[AttachmentApprovalViewController alloc] initWithAttachment:self.attachment delegate:self]; - - [self.navigationController pushViewController:approvalVC animated:YES]; - - // FIXME This implemenation was for the "import with signal" functionality, - // and is now broken. We need to be sure to remove the "import with signal" functionality. - // [SignalApp.sharedApp presentConversationForThread:thread]; -} - -#pragma mark - AttachmentApprovalViewControllerDelegate - -- (void)didApproveAttachment -{ - [ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread]; - [ThreadUtil sendMessageWithAttachment:self.attachment inThread:self.thread messageSender:self.messageSender]; - - // FIXME SHARINGEXTENSION - // Show loading screen and dismiss entire share extension once entirely complete - [self.navigationController popViewControllerAnimated:YES]; -} - -- (void)didCancelAttachment -{ - [self.navigationController popViewControllerAnimated:YES]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/attachments/ShareViewDelegate.swift b/SignalMessaging/attachments/ShareViewDelegate.swift new file mode 100644 index 000000000..084597152 --- /dev/null +++ b/SignalMessaging/attachments/ShareViewDelegate.swift @@ -0,0 +1,12 @@ +// +// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// + +import Foundation +// All Observer methods will be invoked from the main thread. +@objc +public protocol ShareViewDelegate: class { + func shareViewWasCompleted() + func shareViewWasCancelled() + func shareViewFailed(error: Error) +} diff --git a/SignalMessaging/attachments/SendExternalFileViewController.h b/SignalMessaging/attachments/SharingThreadPickerViewController.h similarity index 56% rename from SignalMessaging/attachments/SendExternalFileViewController.h rename to SignalMessaging/attachments/SharingThreadPickerViewController.h index 45f58c895..f221beaea 100644 --- a/SignalMessaging/attachments/SendExternalFileViewController.h +++ b/SignalMessaging/attachments/SharingThreadPickerViewController.h @@ -7,11 +7,14 @@ NS_ASSUME_NONNULL_BEGIN @class SignalAttachment; +@protocol ShareViewDelegate; -@interface SendExternalFileViewController : SelectThreadViewController +@interface SharingThreadPickerViewController : SelectThreadViewController @property (nonatomic) SignalAttachment *attachment; +- (instancetype)initWithShareViewDelegate:(id)shareViewDelegate; + @end NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/attachments/SharingThreadPickerViewController.m b/SignalMessaging/attachments/SharingThreadPickerViewController.m new file mode 100644 index 000000000..d14781b62 --- /dev/null +++ b/SignalMessaging/attachments/SharingThreadPickerViewController.m @@ -0,0 +1,173 @@ +// +// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// + +#import "SharingThreadPickerViewController.h" +#import "Environment.h" +#import "NSString+OWS.h" +#import "SignalApp.h" +#import "ThreadUtil.h" +#import "UIColor+OWS.h" +#import "UIFont+OWS.h" +#import "UIView+OWS.h" +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface SharingThreadPickerViewController () + +@property (nonatomic, readonly) OWSContactsManager *contactsManager; +@property (nonatomic, readonly) OWSMessageSender *messageSender; +@property (nonatomic) TSThread *thread; +@property (nonatomic, readonly, weak) id shareViewDelegate; + +@end + +#pragma mark - + +@implementation SharingThreadPickerViewController + +- (instancetype)initWithShareViewDelegate:(id)shareViewDelegate; +{ + self = [super init]; + if (!self) { + return self; + } + + _shareViewDelegate = shareViewDelegate; + self.selectThreadViewDelegate = self; + + return self; +} + +- (void)loadView +{ + [super loadView]; + + _contactsManager = [Environment current].contactsManager; + _messageSender = [Environment current].messageSender; + + self.title = NSLocalizedString(@"SEND_EXTERNAL_FILE_VIEW_TITLE", @"Title for the 'send external file' view."); +} + +- (BOOL)canSelectBlockedContact +{ + return NO; +} + +- (nullable UIView *)createHeaderWithSearchBar:(UISearchBar *)searchBar +{ + OWSAssert(searchBar) + + const CGFloat contentVMargin + = 0; + + UIView *header = [UIView new]; + header.backgroundColor = [UIColor whiteColor]; + + UIButton *cancelShareButton = [UIButton buttonWithType:UIButtonTypeSystem]; + [header addSubview:cancelShareButton]; + + [cancelShareButton setTitle:[CommonStrings cancelButton] forState:UIControlStateNormal]; + cancelShareButton.userInteractionEnabled = YES; + + [cancelShareButton autoPinEdgeToSuperviewMargin:ALEdgeLeading]; + [cancelShareButton autoPinEdgeToSuperviewMargin:ALEdgeBottom]; + [cancelShareButton setCompressionResistanceHigh]; + [cancelShareButton setContentHuggingHigh]; + + [cancelShareButton addTarget:self + action:@selector(didTapCancelShareButton) + forControlEvents:UIControlEventTouchUpInside]; + + [header addSubview:searchBar]; + [searchBar autoPinEdge:ALEdgeLeading toEdge:ALEdgeTrailing ofView:cancelShareButton withOffset:6]; + [searchBar autoPinEdgeToSuperviewEdge:ALEdgeTrailing]; + [searchBar autoPinEdgeToSuperviewEdge:ALEdgeTop]; + [searchBar autoPinEdgeToSuperviewEdge:ALEdgeBottom]; + + UIView *borderView = [UIView new]; + [header addSubview:borderView]; + + borderView.backgroundColor = [UIColor colorWithRGBHex:0xbbbbbb]; + [borderView autoSetDimension:ALDimensionHeight toSize:0.5]; + [borderView autoPinWidthToSuperview]; + [borderView autoPinEdgeToSuperviewEdge:ALEdgeBottom]; + + // UITableViewController.tableHeaderView must have its height set. + header.frame = CGRectMake(0, 0, 0, (contentVMargin * 2 + searchBar.frame.size.height)); + + return header; +} + +#pragma mark - SelectThreadViewControllerDelegate + +- (void)threadWasSelected:(TSThread *)thread +{ + OWSAssert(self.attachment); + OWSAssert(thread); + self.thread = thread; + + __weak typeof(self) weakSelf = self; + + // FIXME SHARINGEXTENSION + // Handling safety number changes brings in a lot of machinery. + // How do we want to handle this? + // e.g. fingerprint scanning, etc. in the SAE or just redirect the user to the main app? + // BOOL didShowSNAlert = + // [SafetyNumberConfirmationAlert presentAlertIfNecessaryWithRecipientIds:thread.recipientIdentifiers + // confirmationText:[SafetyNumberStrings + // confirmSendButton] + // contactsManager:self.contactsManager + // completion:^(BOOL didConfirm) { + // if (didConfirm) { + // [weakSelf threadWasSelected:thread]; + // } + // }]; + // if (didShowSNAlert) { + // return; + // } + + AttachmentApprovalViewController *approvalVC = + [[AttachmentApprovalViewController alloc] initWithAttachment:self.attachment delegate:self]; + + [self.navigationController pushViewController:approvalVC animated:YES]; +} + +- (void)didTapCancelShareButton +{ + DDLogDebug(@"%@ tapped cancel share button", self.logTag); + [self cancelShareExperience]; +} + +- (void)cancelShareExperience +{ + [self.shareViewDelegate shareViewWasCancelled]; +} + +#pragma mark - AttachmentApprovalViewControllerDelegate + +- (void)didApproveAttachment +{ + [ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread]; + [ThreadUtil sendMessageWithAttachment:self.attachment inThread:self.thread messageSender:self.messageSender]; + + // This is just a temporary hack while testing to hopefully not dismiss too early. + // FIXME Show progress dialog + // FIXME don't dismiss until sending is complete + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [self.shareViewDelegate shareViewWasCompleted]; + }); +} + +- (void)didCancelAttachment +{ + [self cancelShareExperience]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/contacts/SelectThreadViewController.h b/SignalMessaging/contacts/SelectThreadViewController.h index 0cee930fd..f2b11da7f 100644 --- a/SignalMessaging/contacts/SelectThreadViewController.h +++ b/SignalMessaging/contacts/SelectThreadViewController.h @@ -24,7 +24,7 @@ NS_ASSUME_NONNULL_BEGIN // entering a phone number or picking from your contacts. @interface SelectThreadViewController : OWSViewController -@property (nonatomic, weak) id delegate; +@property (nonatomic, weak) id selectThreadViewDelegate; @end diff --git a/SignalMessaging/contacts/SelectThreadViewController.m b/SignalMessaging/contacts/SelectThreadViewController.m index ded70992d..1b05f3c6a 100644 --- a/SignalMessaging/contacts/SelectThreadViewController.m +++ b/SignalMessaging/contacts/SelectThreadViewController.m @@ -71,7 +71,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)createViews { - OWSAssert(self.delegate); + OWSAssert(self.selectThreadViewDelegate); // Search UISearchBar *searchBar = [UISearchBar new]; @@ -82,7 +82,7 @@ NS_ASSUME_NONNULL_BEGIN searchBar.backgroundColor = [UIColor whiteColor]; [searchBar sizeToFit]; - UIView *header = [self.delegate createHeaderWithSearchBar:searchBar]; + UIView *header = [self.selectThreadViewDelegate createHeaderWithSearchBar:searchBar]; // Table _tableViewController = [OWSTableViewController new]; @@ -150,7 +150,7 @@ NS_ASSUME_NONNULL_BEGIN } customRowHeight:[ContactTableViewCell rowHeight] actionBlock:^{ - [weakSelf.delegate threadWasSelected:thread]; + [weakSelf.selectThreadViewDelegate threadWasSelected:thread]; }]]; } @@ -204,11 +204,12 @@ NS_ASSUME_NONNULL_BEGIN - (void)signalAccountWasSelected:(SignalAccount *)signalAccount { OWSAssert(signalAccount); - OWSAssert(self.delegate); + OWSAssert(self.selectThreadViewDelegate); ContactsViewHelper *helper = self.contactsViewHelper; - if ([helper isRecipientIdBlocked:signalAccount.recipientId] && ![self.delegate canSelectBlockedContact]) { + if ([helper isRecipientIdBlocked:signalAccount.recipientId] + && ![self.selectThreadViewDelegate canSelectBlockedContact]) { __weak SelectThreadViewController *weakSelf = self; [BlockListUIUtils showUnblockSignalAccountActionSheet:signalAccount @@ -230,7 +231,7 @@ NS_ASSUME_NONNULL_BEGIN }]; OWSAssert(thread); - [self.delegate threadWasSelected:thread]; + [self.selectThreadViewDelegate threadWasSelected:thread]; } #pragma mark - Filter diff --git a/SignalShareExtension/SAEFailedViewController.swift b/SignalShareExtension/SAEFailedViewController.swift index 8841fe755..418f709d1 100644 --- a/SignalShareExtension/SAEFailedViewController.swift +++ b/SignalShareExtension/SAEFailedViewController.swift @@ -8,7 +8,7 @@ import PureLayout // All Observer methods will be invoked from the main thread. protocol SAEFailedViewDelegate: class { - func shareExtensionWasCancelled() + func shareViewWasCancelled() } class SAEFailedViewController: UIViewController { @@ -92,6 +92,6 @@ class SAEFailedViewController: UIViewController { owsFail("\(self.logTag) missing delegate") return } - delegate.shareExtensionWasCancelled() + delegate.shareViewWasCancelled() } } diff --git a/SignalShareExtension/SAELoadViewController.swift b/SignalShareExtension/SAELoadViewController.swift index 07d9e0f7d..9857d5e93 100644 --- a/SignalShareExtension/SAELoadViewController.swift +++ b/SignalShareExtension/SAELoadViewController.swift @@ -6,20 +6,15 @@ import UIKit import SignalMessaging import PureLayout -// All Observer methods will be invoked from the main thread. -protocol SAELoadViewDelegate: class { - func shareExtensionWasCancelled() -} - class SAELoadViewController: UIViewController { - weak var delegate: SAELoadViewDelegate? + weak var delegate: ShareViewDelegate? var activityIndicator: UIActivityIndicatorView? // MARK: Initializers and Factory Methods - init(delegate: SAELoadViewDelegate) { + init(delegate: ShareViewDelegate) { self.delegate = delegate super.init(nibName: nil, bundle: nil) } @@ -81,6 +76,6 @@ class SAELoadViewController: UIViewController { owsFail("\(self.logTag) missing delegate") return } - delegate.shareExtensionWasCancelled() + delegate.shareViewWasCancelled() } } diff --git a/SignalShareExtension/ShareViewController.swift b/SignalShareExtension/ShareViewController.swift index 44617b070..10d2c0bbe 100644 --- a/SignalShareExtension/ShareViewController.swift +++ b/SignalShareExtension/ShareViewController.swift @@ -10,7 +10,7 @@ import SignalServiceKit import PromiseKit @objc -public class ShareViewController: UINavigationController, SAELoadViewDelegate, SAEFailedViewDelegate { +public class ShareViewController: UINavigationController, ShareViewDelegate, SAEFailedViewDelegate { private var hasInitialRootViewController = false private var isReadyForAppExtensions = false @@ -335,19 +335,27 @@ public class ShareViewController: UINavigationController, SAELoadViewDelegate, S Logger.flush() } - // MARK: SAELoadViewDelegate, SAEFailedViewDelegate + // MARK: ShareViewDelegate, SAEFailedViewDelegate - public func shareExtensionWasCancelled() { + public func shareViewWasCompleted() { self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil) } + public func shareViewWasCancelled() { + self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil) + } + + public func shareViewFailed(error: Error) { + self.extensionContext!.cancelRequest(withError: error) + } + // MARK: Helpers private func presentConversationPicker() { // pause any animation revealing the "loading" screen self.view.layer.removeAllAnimations() self.buildAttachment().then { attachment -> Void in - let conversationPicker = SendExternalFileViewController() + let conversationPicker = SharingThreadPickerViewController(shareViewDelegate: self) let navigationController = UINavigationController(rootViewController: conversationPicker) navigationController.isNavigationBarHidden = true conversationPicker.attachment = attachment @@ -358,7 +366,7 @@ public class ShareViewController: UINavigationController, SAELoadViewDelegate, S OWSAlerts.showAlert(withTitle: alertTitle, message: error.localizedDescription, buttonTitle: CommonStrings.cancelButton) { _ in - self.shareExtensionWasCancelled() + self.shareViewWasCancelled() } owsFail("\(self.logTag) building attachment failed with error: \(error)") }.retainUntilComplete()