123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- // _____ _
- // |_ _| |_ _ _ ___ ___ _ __ __ _
- // | | | ' \| '_/ -_) -_) ' \/ _` |_
- // |_| |_||_|_| \___\___|_|_|_\__,_(_)
- //
- // 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 <https://www.gnu.org/licenses/>.
- #import <MobileCoreServices/UTCoreTypes.h>
- #import "EditableAvatarView.h"
- #import "AppDelegate.h"
- #import "ModalPresenter.h"
- #import "UIDefines.h"
- #import "UIImage+Resize.h"
- #import "RectUtil.h"
- #import "BundleUtil.h"
- #import "AvatarMaker.h"
- #import <RSKImageCropper/RSKImageCropper.h>
- @interface EditableAvatarView () <UIImagePickerControllerDelegate, UINavigationControllerDelegate, RSKImageCropViewControllerDelegate>
- @property UIImagePickerController *imagePicker;
- @property NSInteger takePhotoIndex;
- @property NSInteger chooseExistingIndex;
- @property NSData *currentImageData;
- @end
- @implementation EditableAvatarView
- - (id)initWithCoder:(NSCoder *)aDecoder {
- self = [super initWithCoder:aDecoder];
- if (self) {
- [self setupViews];
- _isReceivedImage = NO;
- }
- return self;
- }
- - (instancetype)initWithFrame:(CGRect)frame {
- self = [super initWithFrame:frame];
- if (self) {
- [self setupViews];
- _isReceivedImage = NO;
- }
- return self;
- }
- - (void)setImageData:(NSData *)imageData {
- _currentImageData = imageData;
- [self updateView];
- }
- - (NSData *)imageData {
- return _currentImageData;
- }
- - (void)setCanDeleteImage:(BOOL)canDeleteImage {
- _canDeleteImage = canDeleteImage;
- [self updatePlaceholderView];
- }
- - (void)setCanChooseImage:(BOOL)canChooseImage {
- _canChooseImage = canChooseImage;
- [self updatePlaceholderView];
- }
- - (void)setupViews {
- _imageView = [[UIImageView alloc] initWithFrame:self.bounds];
- [self addSubview:_imageView];
- _pickImageLabel.userInteractionEnabled = YES;
-
- CGRect rect = CGRectInset(_imageView.frame, 10.0, 10.0);
- _pickImageLabel = [[UILabel alloc] initWithFrame:rect];
- _pickImageLabel.numberOfLines = 3;
- _pickImageLabel.textColor = [Colors main];
- _pickImageLabel.font = [UIFont systemFontOfSize:15.0];
- _pickImageLabel.minimumScaleFactor = 0.6;
- _pickImageLabel.adjustsFontSizeToFitWidth = YES;
- _pickImageLabel.text = NSLocalizedString(@"pick image", nil);
- _pickImageLabel.textAlignment = NSTextAlignmentCenter;
- [self addSubview:_pickImageLabel];
-
- UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tappedImage)];
- [_imageView addGestureRecognizer:tapRecognizer];
- _imageView.userInteractionEnabled = YES;
-
- UITapGestureRecognizer *tapLabelRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tappedImage)];
- [_pickImageLabel addGestureRecognizer:tapLabelRecognizer];
- _pickImageLabel.userInteractionEnabled = YES;
-
- if (@available(iOS 11.0, *)) {
- _imageView.accessibilityIgnoresInvertColors = true;
- }
-
- self.backgroundColor = [UIColor clearColor];
-
- [self updateView];
- }
- - (void)updateView {
- if (_currentImageData) {
- UIImage *image = [UIImage imageWithData:_currentImageData];
- _imageView.image = [AvatarMaker maskImage: image];
- _pickImageLabel.hidden = YES;
- } else {
- _imageView.image = [AvatarMaker avatarWithString:nil size:(_imageView.frame.size.height * [UIScreen mainScreen].scale)];
- _pickImageLabel.hidden = NO;
- }
- }
- - (void)updatePlaceholderView {
- _imageView.userInteractionEnabled = _canDeleteImage || _canChooseImage;
- _pickImageLabel.userInteractionEnabled = _canDeleteImage || _canChooseImage;
- _pickImageLabel.textColor = _canDeleteImage || _canChooseImage ? [Colors main] : [Colors fontPlaceholder];
- }
- - (void)tappedImage {
- if (!_canDeleteImage && !_canChooseImage) {
- return;
- }
-
- [_presentingViewController resignFirstResponder];
-
- if (!_isReceivedImage) {
- /* allow the user to choose a new image or clear the current one */
- UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
- if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] && _canChooseImage) {
- [actionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"take_photo", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
- _imagePicker = [[UIImagePickerController alloc] init];
- _imagePicker.delegate = self;
- _imagePicker.allowsEditing = NO;
- _imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
- _imagePicker.mediaTypes = @[(NSString*)kUTTypeImage];
-
- CGRect rect = [_presentingViewController.view convertRect:self.frame fromView:self.superview];
- [ModalPresenter present:_imagePicker on:_presentingViewController fromRect:rect inView:_presentingViewController.view];
- }]];
- }
- if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary] && _canChooseImage) {
- [actionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"choose_existing", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
- _imagePicker = [[UIImagePickerController alloc] init];
- _imagePicker.delegate = self;
- _imagePicker.allowsEditing = NO;
- _imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
- _imagePicker.mediaTypes = @[(NSString*)kUTTypeImage];
-
- CGRect rect = [_presentingViewController.view convertRect:self.frame fromView:self.superview];
- [ModalPresenter present:_imagePicker on:_presentingViewController fromRect:rect inView:_presentingViewController.view];
- }]];
- }
- if (_currentImageData != nil && _canDeleteImage) {
- [actionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"delete_photo", nil) style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) {
- _currentImageData = nil;
- [self updateView];
- [_delegate avatarImageUpdated:_currentImageData];
- }]];
- }
- [actionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"cancel", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) {
-
- }]];
-
- if (SYSTEM_IS_IPAD == YES || !_presentingViewController.tabBarController) {
- CGRect rect = [_presentingViewController.view convertRect:self.frame fromView:self.superview];
- actionSheet.popoverPresentationController.sourceRect = rect;
- actionSheet.popoverPresentationController.sourceView = self;
- }
-
- [[[AppDelegate sharedAppDelegate] currentTopViewController] presentViewController:actionSheet animated:YES completion:nil];
- }
- }
- #pragma mark - Image picker controller delegate
- - (void)imagePickerController:(UIImagePickerController *)_picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
-
- UIImage *image = info[UIImagePickerControllerEditedImage] ?: info[UIImagePickerControllerOriginalImage];
- RSKImageCropViewController *imageCropViewController = [[RSKImageCropViewController alloc] initWithImage:image];
- imageCropViewController.delegate = self;
- imageCropViewController.cropMode = RSKImageCropModeCircle;
- imageCropViewController.avoidEmptySpaceAroundImage = YES;
- CGSize maskSize = CGSizeMake(kContactImageSize, kContactImageSize);
- imageCropViewController.preferredContentSize = CGSizeMake(maskSize.width, maskSize.height);
- [ModalPresenter dismissPresentedControllerOn:_presentingViewController animated:YES];
- CGRect rect = [_presentingViewController.view convertRect:self.frame fromView:self.superview];
- [ModalPresenter present:imageCropViewController on:_presentingViewController fromRect:rect inView:_presentingViewController.view];
- }
- - (void)imagePickerControllerDidCancel:(UIImagePickerController *)_picker {
- [ModalPresenter dismissPresentedControllerOn:_presentingViewController animated:YES];
- _imagePicker = nil;
-
- [_delegate avatarImageUpdated:_currentImageData];
- }
- #pragma mark - RSKImageCropViewControllerDelegate
- // Crop image has been canceled.
- - (void)imageCropViewControllerDidCancelCrop:(RSKImageCropViewController *)controller
- {
- [ModalPresenter dismissPresentedControllerOn:_presentingViewController animated:YES];
- _imagePicker = nil;
-
- [_delegate avatarImageUpdated:_currentImageData];
- }
- // The original image has been cropped. Additionally provides a rotation angle used to produce image.
- - (void)imageCropViewController:(RSKImageCropViewController *)controller didCropImage:(UIImage *)croppedImage usingCropRect:(CGRect)cropRect rotationAngle:(CGFloat)rotationAngle
- {
- UIImage *resizedImage = [croppedImage resizedImageWithContentMode:UIViewContentModeScaleAspectFit bounds:CGSizeMake(kContactImageSize, kContactImageSize) interpolationQuality:kCGInterpolationHigh];
-
- _currentImageData = UIImageJPEGRepresentation(resizedImage, 0.7f);
- [self updateView];
- [_delegate avatarImageUpdated:_currentImageData];
-
- [ModalPresenter dismissPresentedControllerOn:_presentingViewController animated:YES];
- }
- #pragma mark - Accessibility
- - (BOOL)isAccessibilityElement {
- return YES;
- }
- - (NSString *)accessibilityLabel {
- if (_currentImageData) {
- NSString *image = [BundleUtil localizedStringForKey:@"image"];
- NSString *action = [BundleUtil localizedStringForKey:@"tap_to_change"];
-
- return [NSString stringWithFormat:@"%@, %@", image, action];
- } else {
- return _pickImageLabel.text;
- }
- }
- @end
|