123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536 |
- // _____ _
- // |_ _| |_ _ _ ___ ___ _ __ __ _
- // | | | ' \| '_/ -_) -_) ' \/ _` |_
- // |_| |_||_|_| \___\___|_|_|_\__,_(_)
- //
- // 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 "CompletedIDViewController.h"
- #import "UserSettings.h"
- #import "ContactStore.h"
- #import "MyIdentityStore.h"
- #import "ServerAPIConnector.h"
- #import "PhoneNumberNormalizer.h"
- #import "RectUtil.h"
- #import "ProgressLabel.h"
- #import "IntroQuestionView.h"
- #import "WorkDataFetcher.h"
- #import "MDMSetup.h"
- #import "Threema-Swift.h"
- #import "ConversationUtils.h"
- #import "NibUtil.h"
- #import "AppDelegate.h"
- #define SYNC_TIMEOUT_S 10
- @interface CompletedIDViewController () <IntroQuestionDelegate>
- @property MyIdentityStore *identityStore;
- @property dispatch_semaphore_t syncEmailSemaphore;
- @property dispatch_semaphore_t syncPhoneSemaphore;
- @property dispatch_semaphore_t syncAdressBookSemaphore;
- @property ProgressLabel *emailProgressLabel;
- @property ProgressLabel *phoneProgressLabel;
- @property ProgressLabel *syncProgressLabel;
- @property BOOL isProcessing;
- @property BOOL hasErrors;
- @property NSString *phoneNumber;
- @end
- @implementation CompletedIDViewController
- - (void)viewDidLoad {
- [super viewDidLoad];
-
- _identityStore = [MyIdentityStore sharedMyIdentityStore];
-
- [self setup];
- }
- - (void)viewWillAppear:(BOOL)animated {
- [super viewWillAppear:animated];
-
- [self updateData];
-
- MDMSetup *mdmSetup = [[MDMSetup alloc] initWithSetup:YES];
- if ([mdmSetup skipWizard]) {
- [self finishAction:nil];
- }
- }
- - (void)updateData {
- NSString *nickname = _identityStore.pushFromName;
-
- if (nickname.length == 0) {
- nickname = _identityStore.identity;
- }
-
- self.nicknameValue.text = nickname;
-
- if (_identityStore.createIDEmail.length > 0) {
- self.emailValue.text = _identityStore.createIDEmail;
- } else {
- self.emailValue.text = @"-";
- }
-
- if (_identityStore.linkedMobileNo) {
- self.phoneValue.text = _identityStore.createIDPhone;
- } else if (_identityStore.createIDPhone.length > 0) {
- PhoneNumberNormalizer *normalizer = [PhoneNumberNormalizer sharedInstance];
- NSString *prettyMobileNo;
- _phoneNumber = [normalizer phoneNumberToE164:_identityStore.createIDPhone withDefaultRegion:[PhoneNumberNormalizer userRegion] prettyFormat:&prettyMobileNo];
-
- self.phoneValue.text = prettyMobileNo;
- } else {
- self.phoneValue.text = @"-";
- }
-
- if ([UserSettings sharedUserSettings].syncContacts) {
- self.syncContactValue.text = [BundleUtil localizedStringForKey:@"On"];
- } else {
- self.syncContactValue.text = [BundleUtil localizedStringForKey:@"Off"];
- }
- if (_identityStore.tempSafePassword != nil && _identityStore.tempSafePassword.length > 0) {
- self.enableSafeValue.text = [BundleUtil localizedStringForKey:@"On"];
- } else {
- self.enableSafeValue.text = [BundleUtil localizedStringForKey:@"Off"];
- }
- }
- - (void)adaptToSmallScreen {
- [super adaptToSmallScreen];
-
- CGFloat yOffset = -28.0;
- _nickNameView.frame = [RectUtil offsetRect:_nickNameView.frame byX:0.0 byY:yOffset];
-
- yOffset -= 8.0;
- _linkedToView.frame = [RectUtil offsetRect:_linkedToView.frame byX:0.0 byY:yOffset];
-
- yOffset -= 8.0;
- _syncContactsView.frame = [RectUtil offsetRect:_syncContactsView.frame byX:0.0 byY:yOffset];
-
- yOffset -= 16.0;
- _finishButton.frame = [RectUtil offsetRect:_finishButton.frame byX:0.0 byY:yOffset];
- }
- - (void)setup {
- _finishButton.layer.cornerRadius = 3;
-
- _titleLabel.text = [BundleUtil localizedStringForKey:@"id_completed_title"];
- _nickNameLabel.text = [BundleUtil localizedStringForKey:@"id_completed_nickname"];
- _linkedToLabel.text = [BundleUtil localizedStringForKey:@"id_completed_linked_to"];
- _syncContactsLabel.text = [BundleUtil localizedStringForKey:@"id_completed_sync_contacts"];
- _enableSafeLabel.text = [BundleUtil localizedStringForKey:@"safe_setup_backup_title"];
-
- [_finishButton setTitle:[BundleUtil localizedStringForKey:@"finish"] forState:UIControlStateNormal];
-
- self.scrollView.contentSize = self.mainContentView.frame.size;
-
- _finishButton.backgroundColor = [Colors mainThemeDark];
- [_finishButton setTitleColor:[Colors white] forState:UIControlStateNormal];
-
- if ([AppDelegate hasBottomSafeAreaInsets]) {
- CGFloat iPadSpace = SYSTEM_IS_IPAD ? 50 : 0;
- _finishButton.frame = CGRectMake(_finishButton.frame.origin.x, _finishButton.frame.origin.y - 20.0 - iPadSpace, _finishButton.frame.size.width, _finishButton.frame.size.height);
- }
-
- UIImage *contactImage = [BundleUtil imageNamed:@"Contact"];
- _contactImageView.image = [contactImage imageWithTint:[Colors white]];
-
- _phoneImageView.image = [UIImage imageNamed:@"Phone" inColor:[Colors white]];
- _mailImageView.image = [UIImage imageNamed:@"Mail" inColor:[Colors white]];
-
- if (![LicenseStore requiresLicenseKey]) {
- _emailView.hidden = YES;
- }
- }
- - (void)resetPersistedIDCreateState {
- _identityStore.pendingCreateID = NO;
- }
- - (BOOL)linkEmail {
- if (_identityStore.createIDEmail.length < 1) {
- return NO;
- }
-
- if (_identityStore.linkedEmail.length > 0) {
- return NO;
- }
-
- _syncEmailSemaphore = dispatch_semaphore_create(0);
-
- NSString *email = _identityStore.createIDEmail;
-
- dispatch_async(dispatch_get_main_queue(), ^{
- [self showEmailProgress];
- });
-
- ServerAPIConnector *conn = [[ServerAPIConnector alloc] init];
- [conn linkEmailWithStore:[MyIdentityStore sharedMyIdentityStore] email:email onCompletion:^(BOOL linked) {
- dispatch_async(dispatch_get_main_queue(), ^{
- [_emailProgressLabel hideActivityIndicator];
-
- if (!linked) {
- NSString *message = [BundleUtil localizedStringForKey:@"link_email_sent_title"];
- [_emailProgressLabel showSuccessMessage:message];
- _emailProgressLabel.userInteractionEnabled = NO;
- }
- });
-
- [self signalSemaphore:_syncEmailSemaphore];
- } onError:^(NSError *error) {
- _hasErrors = YES;
- dispatch_async(dispatch_get_main_queue(), ^{
- [_emailProgressLabel showErrorMessage:error.localizedDescription];
- });
-
- [self signalSemaphore:_syncEmailSemaphore];
- }];
-
- dispatch_semaphore_wait(_syncEmailSemaphore, dispatch_time(DISPATCH_TIME_NOW, SYNC_TIMEOUT_S * NSEC_PER_SEC));
- return YES;
- }
- - (BOOL)linkPhone {
- if (_identityStore.createIDPhone.length < 1) {
- return NO;
- }
-
- if (_identityStore.linkedMobileNo.length > 0) {
- return NO;
- }
-
- _syncPhoneSemaphore = dispatch_semaphore_create(0);
-
- if (_phoneNumber == nil) {
- // no normalized phone number - ignore (or try _identityStore.createIDPhone??)
- return NO;
- }
-
- dispatch_async(dispatch_get_main_queue(), ^{
- [self showPhoneProgress];
- });
-
- ServerAPIConnector *conn = [[ServerAPIConnector alloc] init];
- [conn linkMobileNoWithStore:[MyIdentityStore sharedMyIdentityStore] mobileNo:_phoneNumber onCompletion:^(BOOL linked) {
- dispatch_async(dispatch_get_main_queue(), ^{
- [_phoneProgressLabel hideActivityIndicator];
-
- NSString *message = [BundleUtil localizedStringForKey:@"linking_phone_sms_sent"];
- [_phoneProgressLabel showSuccessMessage:message];
- _phoneProgressLabel.userInteractionEnabled = NO;
- });
-
- [self signalSemaphore:_syncPhoneSemaphore];
- } onError:^(NSError *error) {
- _hasErrors = YES;
- dispatch_async(dispatch_get_main_queue(), ^{
- [_phoneProgressLabel showErrorMessage:error.localizedDescription];
- });
-
- [self signalSemaphore:_syncPhoneSemaphore];
- }];
-
- dispatch_semaphore_wait(_syncPhoneSemaphore, dispatch_time(DISPATCH_TIME_NOW, SYNC_TIMEOUT_S * NSEC_PER_SEC));
-
- return YES;
- }
- - (BOOL)syncAdressBook {
- if ([UserSettings sharedUserSettings].syncContacts == NO) {
- return NO;
- }
-
- _syncAdressBookSemaphore = dispatch_semaphore_create(0);
-
- dispatch_async(dispatch_get_main_queue(), ^{
- [self showProgress:_syncContactsView progressValue:_syncContactValue progressText:[BundleUtil localizedStringForKey:@"syncing_contacts"]];
- });
-
- [[ContactStore sharedContactStore] synchronizeAddressBookForceFullSync:YES onCompletion:^(BOOL addressBookAccessGranted) {
- dispatch_async(dispatch_get_main_queue(), ^{
- NSString *message = [BundleUtil localizedStringForKey:@"Done"];
- [_syncProgressLabel showSuccessMessage:message];
- });
-
- [self signalSemaphore:_syncAdressBookSemaphore];
- } onError:^(NSError *error) {
- _hasErrors = YES;
- dispatch_async(dispatch_get_main_queue(), ^{
- [_syncProgressLabel showErrorMessage:error.localizedDescription];
- });
-
- [self signalSemaphore:_syncAdressBookSemaphore];
- }];
-
- dispatch_semaphore_wait(_syncAdressBookSemaphore, dispatch_time(DISPATCH_TIME_NOW, SYNC_TIMEOUT_S * NSEC_PER_SEC));
- return YES;
- }
- - (BOOL)enableSafe {
- SafeConfigManager *safeConfigManager = [[SafeConfigManager alloc] init];
- SafeStore *safeStore = [[SafeStore alloc] initWithSafeConfigManagerAsObject:safeConfigManager serverApiConnector:[[ServerAPIConnector alloc] init]];
- SafeManager *safeManager = [[SafeManager alloc] initWithSafeConfigManagerAsObject:safeConfigManager safeStore:safeStore safeApiService:[[SafeApiService alloc] init]];
-
- // apply Threema Safe password and server config from MDM
- MDMSetup *mdmSetup = [[MDMSetup alloc] initWithSetup:YES];
-
- if ([mdmSetup isSafeBackupPasswordPreset]) {
- self.identityStore.tempSafePassword = [mdmSetup safePassword];
- }
-
- if ([mdmSetup isSafeBackupServerPreset]) {
- [safeConfigManager setCustomServer:[mdmSetup safeServerUrl]];
- [safeConfigManager setServer:[safeStore composeSafeServerAuthWithServer:[mdmSetup safeServerUrl] user:[mdmSetup safeServerUsername] password:[mdmSetup safeServerPassword]].absoluteString];
- }
-
-
- if (self.identityStore.tempSafePassword == nil || self.identityStore.tempSafePassword.length < 8) {
- [safeManager deactivate];
- return NO;
- }
-
- dispatch_async(dispatch_get_main_queue(), ^{
- [self showProgress:_enableSafeView progressValue:_enableSafeValue progressText:[BundleUtil localizedStringForKey:@"safe_preparing"]];
- });
-
- NSError *__autoreleasing _Nullable * _Nullable error = NULL;
- dispatch_sync(dispatch_get_main_queue(), ^{
- [safeManager activateWithIdentity:self.identityStore.identity password:self.identityStore.tempSafePassword error:error];
- });
-
- if (error != nil) {
- _hasErrors = YES;
- return NO;
- } else {
- return YES;
- }
- }
- - (void)signalSemaphore:(dispatch_semaphore_t)semaphore {
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
- dispatch_semaphore_signal(semaphore);
- });
- }
- - (void)arrangeViewsForCompletion {
-
- CGFloat addedPhoneHeight = _phoneView.frame.size.height;
- CGFloat addedEmailHeight = _emailView.frame.size.height;
-
- // double size of email & phone fields
- _phoneView.frame = [RectUtil changeSizeOf:_phoneView.frame deltaX:0.0 deltaY:addedPhoneHeight];
- _emailView.frame = [RectUtil changeSizeOf:_emailView.frame deltaX:0.0 deltaY:addedEmailHeight];
-
- _linkedToView.frame = [RectUtil changeSizeOf:_linkedToView.frame deltaX:0.0 deltaY:addedPhoneHeight + addedEmailHeight];
-
- [UIView animateWithDuration:0.4 delay:0 options:0 animations:^{
- //hide title and increase content (scroll) section
- _titleLabel.alpha = 0.0;
- _scrollView.frame = CGRectMake(_scrollView.frame.origin.x, _scrollView.frame.origin.y - _titleLabel.frame.size.height, _scrollView.frame.size.width, _scrollView.frame.size.height + _titleLabel.frame.size.height);
- CGFloat yOffset = 0;
- _nickNameView.frame = [RectUtil offsetRect:_nickNameView.frame byX:0.0 byY:yOffset];
-
- _linkedToView.frame = [RectUtil offsetRect:_linkedToView.frame byX:0.0 byY:yOffset];
-
- _emailView.frame = [RectUtil offsetRect:_emailView.frame byX:0.0 byY:addedPhoneHeight];
-
- _syncContactsView.frame = [RectUtil offsetRect:_syncContactsView.frame byX:0.0 byY:addedPhoneHeight];
- _enableSafeView.frame = [RectUtil offsetRect:_enableSafeView.frame byX:0.0 byY:addedPhoneHeight];
-
- _finishButton.frame = [RectUtil offsetRect:_finishButton.frame byX:0.0 byY:-yOffset];
- [self.containerDelegate hideControls:YES];
- } completion:nil];
- }
- - (void)showEmailProgress {
- CGFloat yPos = CGRectGetMaxY(_emailValue.frame);
-
- CGRect labelRect = [RectUtil setYPositionOf:_emailValue.frame y:yPos];
-
- _emailProgressLabel = [[ProgressLabel alloc] initWithFrame:labelRect];
- _emailProgressLabel.backgroundColor = [UIColor clearColor];
- _emailProgressLabel.font = [_emailValue.font fontWithSize:14.0];
- _emailProgressLabel.textColor = _emailValue.textColor;
- _emailProgressLabel.alpha = 0.0;
- _emailProgressLabel.text = [BundleUtil localizedStringForKey:@"linking_email"];
- UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tappedEmailProgress)];
- [_emailProgressLabel addGestureRecognizer:tapGesture];
-
- [_emailView addSubview:_emailProgressLabel];
-
- [UIView animateWithDuration:0.4 delay:0 options:0 animations:^{
- _emailProgressLabel.alpha = 1.0;
-
- [_emailProgressLabel showActivityIndicator];
- } completion:nil];
- }
- - (void)showPhoneProgress {
- CGFloat yPos = CGRectGetMaxY(_phoneValue.frame);
-
- CGRect labelRect = [RectUtil setYPositionOf:_phoneValue.frame y:yPos];
-
- _phoneProgressLabel = [[ProgressLabel alloc] initWithFrame:labelRect];
- _phoneProgressLabel.backgroundColor = [UIColor clearColor];
- _phoneProgressLabel.font = [_phoneValue.font fontWithSize:14.0];
- _phoneProgressLabel.textColor = _phoneValue.textColor;
- _phoneProgressLabel.alpha = 0.0;
- _phoneProgressLabel.text = [BundleUtil localizedStringForKey:@"linking_phone"];
- UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tappedPhoneProgress)];
- [_phoneProgressLabel addGestureRecognizer:tapGesture];
-
- [_phoneView addSubview:_phoneProgressLabel];
-
- [UIView animateWithDuration:0.4 delay:0 options:0 animations:^{
- _phoneProgressLabel.alpha = 1.0;
-
- [_phoneProgressLabel showActivityIndicator];
- } completion:nil];
- }
- - (void) showProgress:(UIView*)container progressValue:(UILabel*)value progressText:(NSString*)text {
- CGRect labelRect = value.frame;
-
- _syncProgressLabel = [[ProgressLabel alloc] initWithFrame:labelRect];
- _syncProgressLabel.backgroundColor = [UIColor clearColor];
- _syncProgressLabel.font = [value.font fontWithSize:14.0];
- _syncProgressLabel.textColor = value.textColor;
-
- _syncProgressLabel.alpha = 0.0;
- _syncProgressLabel.text = text;
-
- [container addSubview:_syncProgressLabel];
-
- [UIView animateWithDuration:0.4 delay:0 options:0 animations:^{
- value.alpha = 0.0;
- _syncProgressLabel.alpha = 1.0;
-
- [_syncProgressLabel showActivityIndicator];
- } completion:nil];
- }
- - (BOOL)isInputValid {
- if (_isProcessing) {
- return NO;
- }
-
- return YES;
- }
- - (IBAction)finishAction:(id)sender {
- if (_isProcessing == NO) {
- _isProcessing = YES;
- [self startCompletionProcess];
- } else {
- [self finishCompletionProcess];
- }
- }
- - (void)startCompletionProcess {
- _finishButton.userInteractionEnabled = NO;
- _finishButton.alpha = 0.0;
-
- [self resetPersistedIDCreateState];
-
- [self arrangeViewsForCompletion];
-
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
- NSInteger timout = 2000;
-
- if ([self linkPhone]) {
- timout += 1000;
- }
-
- if ([self linkEmail]) {
- timout += 1000;
- }
- if ([self syncAdressBook]) {
- timout += 500;
- }
-
- if ([self enableSafe]) {
- timout += 500;
- }
-
- // do not show Threema Safe Intro after setup wizard
- [[UserSettings sharedUserSettings] setSafeIntroShown:YES];
- if (_hasErrors == NO) {
- // no errors - continue after timeout
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timout * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{
- [_delegate completedIDSetup];
- });
- } else {
- // user needs to confirm
- dispatch_async(dispatch_get_main_queue(), ^{
- [_finishButton setTitle:[BundleUtil localizedStringForKey:@"Done"] forState:UIControlStateNormal];
- _finishButton.userInteractionEnabled = YES;
- _finishButton.alpha = 1.0;
- });
- }
-
- _identityStore.createIDPhone = nil;
- _identityStore.createIDEmail = nil;
- _identityStore.tempSafePassword = nil;
- });
- }
- - (void)finishCompletionProcess {
- dispatch_async(dispatch_get_main_queue(), ^{
- [_delegate completedIDSetup];
- });
- }
- #pragma mark - gesture recognizers
- - (void)tappedPhoneProgress {
- [self showErrorText:_phoneProgressLabel.text];
- }
- - (void)tappedEmailProgress {
- [self showErrorText:_emailProgressLabel.text];
- }
- - (void)showErrorText:(NSString *)errorText {
- IntroQuestionView *view = (IntroQuestionView *)[NibUtil loadViewFromNibWithName:@"IntroQuestionView"];
- view.showOnlyOkButton = YES;
- view.questionLabel.text = errorText;
- view.delegate = self;
- view.frame = [RectUtil rect:view.frame centerIn:self.view.frame round:YES];
-
- [self.view addSubview:view];
-
- [self showMessageView:view];
- }
- - (void)selectedOk:(IntroQuestionView *)sender {
- [self hideMessageView:sender ignoreControls:YES];
- }
- @end
|