Cancelling dismisses share extension, remove "import with signal"

Usinig the new ShareViewDelegate to dismiss the share extension, might
have broken the "import with signal" functionality. But because we
want to remove it anyway, I've done that now, rather than fix it up.

// FREEBIE
This commit is contained in:
Michael Kirk 2017-12-07 14:52:38 -05:00
parent 2cd3ce62f9
commit 3ecf0a7537
14 changed files with 244 additions and 396 deletions

View File

@ -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 = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
3400C7911EAF89CD008A8584 /* SendExternalFileViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SendExternalFileViewController.m; sourceTree = "<group>"; };
3400C7901EAF89CD008A8584 /* SharingThreadPickerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SharingThreadPickerViewController.h; sourceTree = "<group>"; };
3400C7911EAF89CD008A8584 /* SharingThreadPickerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SharingThreadPickerViewController.m; sourceTree = "<group>"; };
3400C7941EAF99F4008A8584 /* SelectThreadViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SelectThreadViewController.h; sourceTree = "<group>"; };
3400C7951EAF99F4008A8584 /* SelectThreadViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SelectThreadViewController.m; sourceTree = "<group>"; };
3400C7971EAFB772008A8584 /* ThreadViewHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadViewHelper.h; sourceTree = "<group>"; };
@ -812,6 +813,7 @@
45AE48501E0732D6004D96C2 /* TurnServerInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TurnServerInfo.swift; sourceTree = "<group>"; };
45B201741DAECBFD00C461E0 /* Signal-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Signal-Bridging-Header.h"; sourceTree = "<group>"; };
45BB93371E688E14001E3939 /* UIDevice+featureSupport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIDevice+featureSupport.swift"; sourceTree = "<group>"; };
45BC829C1FD9C4B400011CF3 /* ShareViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewDelegate.swift; sourceTree = "<group>"; };
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 = "<group>"; };
45C0DC1D1E69011F00E04C47 /* UIStoryboard+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIStoryboard+OWS.swift"; sourceTree = "<group>"; };
@ -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 = "<group>";
@ -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 */,
);

View File

@ -15,12 +15,6 @@
<string>Signal</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>LSItemContentTypes</key>
<array>
<string>public.archive</string>
<string>public.content</string>
<string>public.data</string>
</array>
</dict>
</array>
<key>CFBundleExecutable</key>

View File

@ -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);

View File

@ -24,7 +24,7 @@ FOUNDATION_EXPORT const unsigned char SignalMessagingVersionString[];
#import <SignalMessaging/OWSMath.h>
#import <SignalMessaging/OWSProfileManager.h>
#import <SignalMessaging/Release.h>
#import <SignalMessaging/SendExternalFileViewController.h>
#import <SignalMessaging/SharingThreadPickerViewController.h>
#import <SignalMessaging/UIColor+OWS.h>
#import <SignalMessaging/UIFont+OWS.h>
#import <SignalMessaging/UIImage+OWS.h>

View File

@ -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()
}
}

View File

@ -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 <SignalMessaging/SignalMessaging-Swift.h>
#import <SignalServiceKit/OWSMessageSender.h>
#import <SignalServiceKit/TSThread.h>
NS_ASSUME_NONNULL_BEGIN
@interface SendExternalFileViewController () <SelectThreadViewControllerDelegate,
AttachmentApprovalViewControllerDelegate>
@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

View File

@ -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)
}

View File

@ -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>)shareViewDelegate;
@end
NS_ASSUME_NONNULL_END

View File

@ -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 <SignalMessaging/SignalMessaging-Swift.h>
#import <SignalServiceKit/OWSMessageSender.h>
#import <SignalServiceKit/TSThread.h>
NS_ASSUME_NONNULL_BEGIN
@interface SharingThreadPickerViewController () <SelectThreadViewControllerDelegate,
AttachmentApprovalViewControllerDelegate>
@property (nonatomic, readonly) OWSContactsManager *contactsManager;
@property (nonatomic, readonly) OWSMessageSender *messageSender;
@property (nonatomic) TSThread *thread;
@property (nonatomic, readonly, weak) id<ShareViewDelegate> shareViewDelegate;
@end
#pragma mark -
@implementation SharingThreadPickerViewController
- (instancetype)initWithShareViewDelegate:(id<ShareViewDelegate>)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

View File

@ -24,7 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
// entering a phone number or picking from your contacts.
@interface SelectThreadViewController : OWSViewController
@property (nonatomic, weak) id<SelectThreadViewControllerDelegate> delegate;
@property (nonatomic, weak) id<SelectThreadViewControllerDelegate> selectThreadViewDelegate;
@end

View File

@ -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

View File

@ -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()
}
}

View File

@ -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()
}
}

View File

@ -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()