diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index ba6958e90..1b858cb17 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -1665,6 +1665,9 @@ com.apple.VPNLite = { enabled = 0; }; + com.apple.iCloud = { + enabled = 1; + }; }; }; D221A0A9169C9E5F00537ABF = { diff --git a/Signal/Signal.entitlements b/Signal/Signal.entitlements index 903def2af..dfec421ea 100644 --- a/Signal/Signal.entitlements +++ b/Signal/Signal.entitlements @@ -4,5 +4,17 @@ aps-environment development + com.apple.developer.icloud-container-identifiers + + iCloud.$(CFBundleIdentifier) + + com.apple.developer.icloud-services + + CloudDocuments + + com.apple.developer.ubiquity-container-identifiers + + iCloud.$(CFBundleIdentifier) + diff --git a/Signal/src/ViewControllers/MessagesViewController.m b/Signal/src/ViewControllers/MessagesViewController.m index dcecdee09..72d7aa9fb 100644 --- a/Signal/src/ViewControllers/MessagesViewController.m +++ b/Signal/src/ViewControllers/MessagesViewController.m @@ -186,7 +186,10 @@ typedef enum : NSUInteger { #pragma mark - -@interface MessagesViewController () { +@interface MessagesViewController () { UIImage *tappedImage; BOOL isGroupConversation; } @@ -2182,6 +2185,87 @@ typedef enum : NSUInteger { [self presentViewController:actionSheetController animated:YES completion:nil]; } + +#pragma mark - Attachment Picking: Documents + +- (void)showAttachmentDocumentPicker +{ + NSString *allItems = (__bridge NSString *)kUTTypeData; + NSArray *documentTypes = @[ allItems ]; + // UIDocumentPickerModeImport copies to a temp file within our container. + // It uses more memory than "open" but let's us avoid working with security scoped URLs. + UIDocumentPickerMode pickerMode = UIDocumentPickerModeImport; + UIDocumentMenuViewController *menuController = + [[UIDocumentMenuViewController alloc] initWithDocumentTypes:documentTypes inMode:pickerMode]; + menuController.delegate = self; + [self presentViewController:menuController animated:YES completion:nil]; +} + +#pragma mark UIDocumentMenuDelegate + +- (void)documentMenu:(UIDocumentMenuViewController *)documentMenu + didPickDocumentPicker:(UIDocumentPickerViewController *)documentPicker +{ + documentPicker.delegate = self; + [self presentViewController:documentPicker animated:YES completion:nil]; +} + +#pragma mark UIDocumentPickerDelegate +- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url +{ + DDLogDebug(@"%@ Picked document at url: %@", self.tag, url); + NSData *attachmentData = [NSData dataWithContentsOfURL:url]; + + NSString *type; + NSError *error; + [url getResourceValue:&type forKey:NSURLTypeIdentifierKey error:&error]; + if (error) { + DDLogError(@"%@ Determining type of picked document at url: %@ failed with error: %@", self.tag, url, error); + OWSAssert(NO); + } + + if (!type) { + DDLogDebug(@"%@ falling back to default filetype for picked document at url: %@", self.tag, url); + OWSAssert(NO); + type = (__bridge NSString *)kUTTypeData; + } + + NSString *filename = url.lastPathComponent; + if (!filename) { + DDLogDebug(@"%@ Unable to determine filename from url: %@", self.tag, url); + OWSAssert(NO); + filename = NSLocalizedString( + @"ATTACHMENT_DEFAULT_FILENAME", @"Generic filename for an attachment with no known name"); + } + + if (!attachmentData || attachmentData.length == 0) { + DDLogError(@"%@ attachment data was unexpectedly empty for picked document url: %@", self.tag, url); + OWSAssert(NO); + UIAlertController *alertController = [UIAlertController + alertControllerWithTitle:NSLocalizedString(@"ATTACHMENT_PICKER_DOCUMENTS_FAILED_ALERT_TITLE", + @"Alert title when picking a document fails for an unknown reason") + message:nil + preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *dismissAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"DISMISS_BUTTON_TEXT", nil) + style:UIAlertActionStyleCancel + handler:nil]; + [alertController addAction:dismissAction]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [self presentViewController:alertController animated:YES completion:nil]; + }); + return; + } + + OWSAssert(attachmentData); + OWSAssert(type); + OWSAssert(filename); + SignalAttachment *attachment = + [[SignalAttachment alloc] initWithData:attachmentData dataUTI:type filename:filename]; + [ThreadUtil sendMessageWithAttachment:attachment inThread:self.thread messageSender:self.messageSender]; +} + #pragma mark - UIImagePickerController /* @@ -2680,7 +2764,16 @@ typedef enum : NSUInteger { [self chooseFromLibrary]; }]; [actionSheetController addAction:chooseMediaAction]; - + + UIAlertAction *chooseDocumentAction = + [UIAlertAction actionWithTitle:NSLocalizedString(@"MEDIA_FROM_DOCUMENT_PICKER_BUTTON", + @"action sheet button title when choosing attachment type") + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *_Nonnull action) { + [self showAttachmentDocumentPicker]; + }]; + [actionSheetController addAction:chooseDocumentAction]; + [self presentViewController:actionSheetController animated:true completion:nil]; } diff --git a/Signal/src/views/AttachmentPointerView.swift b/Signal/src/views/AttachmentPointerView.swift index f5c03ed6f..931797f29 100644 --- a/Signal/src/views/AttachmentPointerView.swift +++ b/Signal/src/views/AttachmentPointerView.swift @@ -14,7 +14,7 @@ class AttachmentPointerView: UIView { let isIncoming: Bool let filename: String let attachmentPointer: TSAttachmentPointer - let genericFilename = NSLocalizedString("ATTACHMENT_DOWNLOADING_DEFAULT_ATTACHMENT_LABEL", comment: "Generic name label when downloading an attachment with no known name.") + let genericFilename = NSLocalizedString("ATTACHMENT_DEFAULT_FILENAME", comment: "Generic filename for an attachment with no known name") var progress: CGFloat = 0 { didSet { diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 142ef2af8..0cdff1500 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -61,8 +61,8 @@ /* Label for 'send' button in the 'attachment approval' dialog. */ "ATTACHMENT_APPROVAL_SEND_BUTTON" = "Send"; -/* Generic name label when downloading an attachment with no known name. */ -"ATTACHMENT_DOWNLOADING_DEFAULT_ATTACHMENT_LABEL" = "Attachment"; +/* Generic filename for an attachment with no known name */ +"ATTACHMENT_DEFAULT_FILENAME" = "Attachment"; /* Status label when an attachment download has failed. */ "ATTACHMENT_DOWNLOADING_STATUS_FAILED" = "Failed. Tap to retry."; @@ -100,6 +100,9 @@ /* Accessibility label for attaching photos */ "ATTACHMENT_LABEL" = "Attachment"; +/* Alert title when picking a document fails for an unknown reason */ +"ATTACHMENT_PICKER_DOCUMENTS_FAILED_ALERT_TITLE" = "Failed to choose document."; + /* An explanation of the consequences of blocking another user. */ "BLOCK_BEHAVIOR_EXPLANATION" = "Blocked users will not be able to call you or send you messages."; @@ -589,6 +592,9 @@ /* media picker option to take photo or video */ "MEDIA_FROM_CAMERA_BUTTON" = "Camera"; +/* action sheet button title when choosing attachment type */ +"MEDIA_FROM_DOCUMENT_PICKER_BUTTON" = "Document"; + /* media picker option to choose from library */ "MEDIA_FROM_LIBRARY_BUTTON" = "Photo Library";