// _____ _
// |_ _| |_ _ _ ___ ___ _ __ __ _
// | | | ' \| '_/ -_) -_) ' \/ _` |_
// |_| |_||_|_| \___\___|_|_|_\__,_(_)
//
// Threema iOS Client
// Copyright (c) 2015-2020 Threema GmbH
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License, version 3,
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
#import "DocumentPicker.h"
#import "UTIConverter.h"
#import "ModalPresenter.h"
#import "BundleUtil.h"
#import "MBProgressHUD.h"
#import "FeatureMaskChecker.h"
#import "ContactUtil.h"
#import "FileMessageSender.h"
#import
#import
#import
@interface DocumentPicker ()
@property UIViewController *presentingViewController;
@property Conversation *conversation;
@end
@implementation DocumentPicker
static DocumentPicker *pickerStrongReference;
+ (instancetype)documentPickerForViewController:(UIViewController *)presentingViewController conversation:(Conversation *)conversation {
DocumentPicker *picker = [[DocumentPicker alloc] init];
picker.presentingViewController = presentingViewController;
picker.conversation = conversation;
return picker;
}
- (void)show {
NSSet *conversations = [NSSet setWithObject:_conversation];
FeatureMaskChecker *featureMaskChecker = [[FeatureMaskChecker alloc] init];
[featureMaskChecker checkFileTransferFor:conversations presentAlarmOn:_presentingViewController onSuccess:^{
[self showPicker];
} onFailure:^{
;//nop
}];
}
- (void)showPicker {
NSArray *types = @[UTTYPE_ITEM, UTTYPE_DATA, UTTYPE_CONTENT, UTTYPE_ARCHIVE, UTTYPE_CONTACT, UTTYPE_MESSAGE];
UIDocumentMenuViewController *controller = [[UIDocumentMenuViewController alloc] initWithDocumentTypes:types inMode:UIDocumentPickerModeImport];
controller.delegate = self;
NSString *title = [BundleUtil localizedStringForKey:@"contacts"];
UIImage *image = [BundleUtil imageNamed:@"ThumbBusinessContact.png"];
[controller addOptionWithTitle:title image:image order:UIDocumentMenuOrderFirst handler:^{
[self checkPermissionAndShowContactPicker];
}];
pickerStrongReference = self;
[self showController:controller];
}
- (void)showController:(UIViewController *)controller {
if (CGRectIsNull(_popoverSourceRect)) {
[ModalPresenter present:controller on:_presentingViewController];
} else {
[ModalPresenter present:controller on:_presentingViewController fromRect:_popoverSourceRect inView:_presentingViewController.view];
}
}
- (void)checkPermissionAndShowContactPicker {
if ([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts] == CNAuthorizationStatusAuthorized) {
[self showContactPicker];
}
else if ([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts] == CNAuthorizationStatusDenied) {
[self showContactAlert];
}
else {
CNContactStore *cnAddressBook = [CNContactStore new];
[cnAddressBook requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted) {
[self showContactPicker];
} else {
[self showContactAlert];
}
}];
}
}
- (void)showContactPicker {
CNContactPickerViewController *picker = [[CNContactPickerViewController alloc] init];
picker.delegate = self;
picker.modalPresentationStyle = UIModalPresentationFormSheet;
[self showController:picker];
}
- (void)showContactAlert {
NSString *title = NSLocalizedString(@"no_contacts_permission_title", nil);
NSString *message = NSLocalizedString(@"no_contacts_permission_message", nil);
[self showAlertWithTitle:title message:message closeOnOk:YES];
}
- (void)sendItem:(URLSenderItem *)item {
NSString *messageFormat = NSLocalizedString(@"send_file_message", nil);
NSString *message = [NSString stringWithFormat:messageFormat, [item getName], _conversation.displayName];
NSString *title = NSLocalizedString(@"send_file_title", nil);
__block UITextField *captionTextField = nil;
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
if (@available(iOS 13.0, *)) {
textField.textColor = [Colors fontNormal];
}
textField.placeholder = [BundleUtil localizedStringForKey:@"optional_caption"];
captionTextField = textField;
}];
NSString *ok = [BundleUtil localizedStringForKey:@"ok"];
NSString *cancel = [BundleUtil localizedStringForKey:@"cancel"];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:ok style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
[MBProgressHUD showHUDAddedTo:_presentingViewController.view animated:YES];
if (captionTextField.text.length > 0) {
item.caption = captionTextField.text;
}
FileMessageSender *sender = [[FileMessageSender alloc] init];
sender.uploadProgressDelegate = self;
[sender sendItem:item inConversation:_conversation];
}];
[alertController addAction:defaultAction];
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:cancel style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
pickerStrongReference = nil;
}];
[alertController addAction:cancelAction];
[_presentingViewController presentViewController:alertController animated:YES completion:nil];
}
#pragma mark - UIDocumentPickerDelegate
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url {
URLSenderItem *item = [URLSenderItemCreator getSenderItemFor:url];
[self sendItem:item];
}
#pragma mark - UIDocumentMenuDelegate
- (void)documentMenu:(UIDocumentMenuViewController *)documentMenu didPickDocumentPicker:(UIDocumentPickerViewController *)documentPicker {
documentPicker.delegate = self;
[self showController:documentPicker];
}
#pragma mark - UploadProgressDelegate
- (BOOL)blobMessageSenderUploadShouldCancel:(BlobMessageSender *)blobMessageSender {
return NO;
}
- (void)blobMessageSender:(BlobMessageSender *)blobMessageSender uploadProgress:(NSNumber *)progress forMessage:(BaseMessage *)message {
// hide as soon as progress starts which is visible in message bubble
[MBProgressHUD hideHUDForView:_presentingViewController.view animated:YES];
}
- (void)blobMessageSender:(BlobMessageSender *)blobMessageSender uploadFailedForMessage:(BaseMessage *)message error:(UploadError)error {
[MBProgressHUD hideHUDForView:_presentingViewController.view animated:YES];
NSString *errorTitle = [BundleUtil localizedStringForKey:@"error_sending_failed"];
NSString *errorMessage = [FileMessageSender messageForError:error];
[self showAlertWithTitle:errorTitle message:errorMessage closeOnOk:NO];
}
- (void)blobMessageSender:(BlobMessageSender *)blobMessageSender uploadSucceededForMessage:(BaseMessage *)message {
pickerStrongReference = nil;
}
- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message closeOnOk:(BOOL)closeOnOk {
[UIAlertTemplate showAlertWithOwner:_presentingViewController title:title message:message actionOk:^(UIAlertAction * _Nonnull okAction) {
pickerStrongReference = nil;
}];
}
#pragma mark - People picker delegate
-(void) contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact{
NSData *vCardData = [ContactUtil vCardDataForCnContact:contact];
URLSenderItem *item = [URLSenderItem itemWithData:vCardData fileName:nil type:UTTYPE_VCARD renderType:@0 sendAsFile:true];
[picker dismissViewControllerAnimated:YES completion:^{
[self sendItem:item];
}];
}
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContactProperty:(CNContactProperty *)contactProperty {
[picker dismissViewControllerAnimated:YES completion:nil];
}
-(void)contactPickerDidCancel:(CNContactPickerViewController *)picker {
[picker dismissViewControllerAnimated:YES completion:nil];
}
@end