MyIdentityViewController.m 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. // _____ _
  2. // |_ _| |_ _ _ ___ ___ _ __ __ _
  3. // | | | ' \| '_/ -_) -_) ' \/ _` |_
  4. // |_| |_||_|_| \___\___|_|_|_\__,_(_)
  5. //
  6. // Threema iOS Client
  7. // Copyright (c) 2012-2020 Threema GmbH
  8. //
  9. // This program is free software: you can redistribute it and/or modify
  10. // it under the terms of the GNU Affero General Public License, version 3,
  11. // as published by the Free Software Foundation.
  12. //
  13. // This program is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU Affero General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Affero General Public License
  19. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. #import <MobileCoreServices/UTCoreTypes.h>
  21. #import "MyIdentityViewController.h"
  22. #import "MyIdentityStore.h"
  23. #import "ScanIdentityController.h"
  24. #import "ServerAPIConnector.h"
  25. #import "KKPasscodeLock.h"
  26. #import "ContactStore.h"
  27. #import "PasswordCallback.h"
  28. #import "CreatePasswordTrigger.h"
  29. #import "BackupIdentityViewController.h"
  30. #import "MBProgressHUD.h"
  31. #import "RevocationKeyHandler.h"
  32. #import "QRCodeGenerator.h"
  33. #import "NSString+Hex.h"
  34. #import "UserReminder.h"
  35. #import "AppDelegate.h"
  36. #import "UIImage+ColoredImage.h"
  37. #import "BundleUtil.h"
  38. #import "LicenseStore.h"
  39. #import "BrandingUtils.h"
  40. #import "UserSettings.h"
  41. #import "AvatarMaker.h"
  42. #import "FullscreenImageViewController.h"
  43. #import "ModalNavigationController.h"
  44. #import "ValidationLogger.h"
  45. #import "MDMSetup.h"
  46. #import "Threema-Swift.h"
  47. #import "ActivityUtil.h"
  48. #define SEGUE_NICKNAME @"EditProfile"
  49. #define SEGUE_SAFE_SETUP @"segueSafeSetup"
  50. #define THREEMA_ID_SHARE_LINK @"https://threema.id/"
  51. @interface MyIdentityViewController () <PasswordCallback, UIScrollViewDelegate, ModalNavigationControllerDelegate>
  52. @property RevocationKeyHandler *revocationKeyHandler;
  53. @end
  54. @implementation MyIdentityViewController {
  55. UIView *coverView;
  56. UIImageView *zoomingQrImageView;
  57. CGRect qrRect;
  58. CGRect qrZoomedRect;
  59. UIAlertController *deleteActionSheet;
  60. MDMSetup *mdmSetup;
  61. }
  62. @synthesize nickNameTitleLabel;
  63. @synthesize threemaIdTitleLabel;
  64. @synthesize threemaIdLabel;
  65. @synthesize threemaSafeLabel;
  66. @synthesize nickNameLabel;
  67. @synthesize keyFingerprintLabel;
  68. @synthesize qrBackgroundImageView;
  69. - (instancetype)initWithCoder:(NSCoder *)coder
  70. {
  71. self = [super initWithCoder:coder];
  72. if (self) {
  73. mdmSetup = [[MDMSetup alloc] initWithSetup:NO];
  74. }
  75. return self;
  76. }
  77. - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
  78. if ([segue.destinationViewController isKindOfClass:[ModalNavigationController class]]) {
  79. ModalNavigationController *nav = segue.destinationViewController;
  80. nav.modalDelegate = self;
  81. }
  82. }
  83. - (void)viewDidLoad {
  84. [super viewDidLoad];
  85. self.navigationController.interactivePopGestureRecognizer.enabled = YES;
  86. self.navigationController.interactivePopGestureRecognizer.delegate = nil;
  87. if (![ScanIdentityController canScan])
  88. self.navigationItem.rightBarButtonItem = nil;
  89. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
  90. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appResignActive:) name:UIApplicationWillResignActiveNotification object:nil];
  91. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateView) name:@"ThreemaIdentityLinkedWithMobileNo" object:nil];
  92. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(colorThemeChanged:) name:kNotificationColorThemeChanged object:nil];
  93. _revocationKeyHandler = [[RevocationKeyHandler alloc] init];
  94. [BrandingUtils updateTitleLogoOfNavigationItem:self.navigationItem navigationController:self.navigationController];
  95. UITapGestureRecognizer *imageTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tappedHeaderView)];
  96. [_imageView addGestureRecognizer:imageTapRecognizer];
  97. _imageView.accessibilityTraits = UIAccessibilityTraitButton;
  98. _imageView.isAccessibilityElement = NO;
  99. UITapGestureRecognizer *editTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tappedHeaderView)];
  100. [_editButton addGestureRecognizer:editTapRecognizer];
  101. _editButton.accessibilityTraits = UIAccessibilityTraitNone;
  102. _editButton.accessibilityLabel = [BundleUtil localizedStringForKey:@"edit_profile"];
  103. UITapGestureRecognizer *qrCodeTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(showFullScreenQrView)];
  104. [_qrCodeButton addGestureRecognizer:qrCodeTapRecognizer];
  105. _qrCodeButton.accessibilityTraits = UIAccessibilityTraitNone;
  106. _qrCodeButton.accessibilityLabel = [BundleUtil localizedStringForKey:@"qr_code"];
  107. UITapGestureRecognizer *shareIdTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tappedShareThreemaId)];
  108. [_shareIdButton addGestureRecognizer:shareIdTapRecognizer];
  109. _shareIdButton.accessibilityTraits = UIAccessibilityTraitNone;
  110. _shareIdButton.accessibilityLabel = [BundleUtil localizedStringForKey:@"share_id"];
  111. if (@available(iOS 11.0, *)) {
  112. _imageView.accessibilityIgnoresInvertColors = true;
  113. }
  114. }
  115. - (void)dealloc {
  116. [[NSNotificationCenter defaultCenter] removeObserver:self];
  117. }
  118. - (BOOL)shouldAutorotate {
  119. return YES;
  120. }
  121. -(UIInterfaceOrientationMask)supportedInterfaceOrientations {
  122. if (SYSTEM_IS_IPAD) {
  123. return UIInterfaceOrientationMaskAll;
  124. }
  125. return UIInterfaceOrientationMaskAllButUpsideDown;
  126. }
  127. - (void)appForeground:(NSNotification*)notification {
  128. /* must update view as the user may have come back from doing e-mail verification */
  129. [self updateView];
  130. }
  131. - (void)appResignActive:(NSNotification*)notification {
  132. [self hideFullScreenQrViewAnimated:NO];
  133. }
  134. - (void)colorThemeChanged:(NSNotification*)notification {
  135. [BrandingUtils updateTitleLogoOfNavigationItem:self.navigationItem navigationController:self.navigationController];
  136. [self updateColors];
  137. }
  138. - (void)viewWillAppear:(BOOL)animated {
  139. [super viewWillAppear:animated];
  140. [self hideFullScreenQrViewAnimated:NO];
  141. [self updateView];
  142. if (@available(iOS 11.0, *)) {
  143. self.navigationItem.largeTitleDisplayMode = [UserSettings sharedUserSettings].largeTitleDisplayMode;
  144. }
  145. // iOS fix where the logo is moved to the right sometimes
  146. if (self.navigationController.navigationBar.frame.size.height == 44.0 && [LicenseStore requiresLicenseKey]) {
  147. [BrandingUtils updateTitleLogoOfNavigationItem:self.navigationItem navigationController:self.navigationController];
  148. }
  149. else if (self.navigationController.navigationBar.frame.size.height == 44.0 && ![LicenseStore requiresLicenseKey] && self.navigationItem.titleView != nil) {
  150. [BrandingUtils updateTitleLogoOfNavigationItem:self.navigationItem navigationController:self.navigationController];
  151. }
  152. }
  153. - (void)viewWillDisappear:(BOOL)animated {
  154. [self hideFullScreenQrViewAnimated:NO];
  155. [super viewWillDisappear:animated];
  156. }
  157. - (void)viewWillLayoutSubviews {
  158. [super viewWillLayoutSubviews];
  159. UIView *header = self.tableView.tableHeaderView;
  160. if (header) {
  161. CGSize newSize = [header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
  162. header.frame = CGRectMake(header.frame.origin.x, header.frame.origin.y, header.frame.size.width, newSize.height);
  163. }
  164. }
  165. - (void)updatePendingEmailLink {
  166. /* check status of e-mail link */
  167. ServerAPIConnector *conn = [[ServerAPIConnector alloc] init];
  168. [conn checkLinkEmailStatus:[MyIdentityStore sharedMyIdentityStore] email:[MyIdentityStore sharedMyIdentityStore].linkedEmail onCompletion:^(BOOL linked) {
  169. if (linked) {
  170. [MyIdentityStore sharedMyIdentityStore].linkEmailPending = NO;
  171. self.linkedEmailLabel.text = [MyIdentityStore sharedMyIdentityStore].linkedEmail;
  172. }
  173. } onError:^(NSError *error) {}];
  174. }
  175. - (void)updateView {
  176. _scanQrCodeBarButtonItem.accessibilityLabel = [BundleUtil localizedStringForKey:@"scan_identity"];
  177. threemaIdLabel.text = [MyIdentityStore sharedMyIdentityStore].identity;
  178. threemaIdLabel.accessibilityLabel = [NSString stringWithFormat:@"%@: %@", NSLocalizedString(@"my_threema_id", @""), [MyIdentityStore sharedMyIdentityStore].identity];
  179. keyFingerprintLabel.text = [MyIdentityStore sharedMyIdentityStore].keyFingerprint;
  180. UIImage *qrCodeImage = [self renderQrCodeWithDimension:self.qrCodeButton.frame.size.width * [UIScreen mainScreen].scale];
  181. switch ([Colors getTheme]) {
  182. case ColorThemeDark:
  183. case ColorThemeDarkWork:
  184. qrCodeImage = [qrCodeImage imageWithTint:[UIColor whiteColor]];
  185. break;
  186. default:
  187. qrCodeImage = [qrCodeImage imageWithTint:[UIColor blackColor]];
  188. break;
  189. }
  190. [self.qrCodeButton setImage:qrCodeImage forState:UIControlStateNormal];
  191. /* linked e-mail */
  192. if ([MyIdentityStore sharedMyIdentityStore].linkedEmail != nil) {
  193. if ([MyIdentityStore sharedMyIdentityStore].linkEmailPending) {
  194. self.linkedEmailLabel.text = NSLocalizedString(@"(pending)", nil);
  195. [self updatePendingEmailLink];
  196. } else {
  197. self.linkedEmailLabel.text = [MyIdentityStore sharedMyIdentityStore].linkedEmail;
  198. }
  199. } else {
  200. self.linkedEmailLabel.text = @" ";
  201. }
  202. /* linked mobile number */
  203. if ([MyIdentityStore sharedMyIdentityStore].linkMobileNoPending) {
  204. self.linkedMobileNoLabel.text = NSLocalizedString(@"enter_code", nil);
  205. } else {
  206. if ([MyIdentityStore sharedMyIdentityStore].linkedMobileNo != nil)
  207. self.linkedMobileNoLabel.text = [NSString stringWithFormat:@"+%@", [MyIdentityStore sharedMyIdentityStore].linkedMobileNo];
  208. else
  209. self.linkedMobileNoLabel.text = @" ";
  210. }
  211. [self updateNickname];
  212. [self updateProfilePicture];
  213. [self updateColors];
  214. [self triggerRevocationKeyCheck];
  215. [self disabledCellsForMDM];
  216. [self updateThreemaSafe];
  217. }
  218. - (void)updateNickname {
  219. if ([MyIdentityStore sharedMyIdentityStore].pushFromName != nil && [MyIdentityStore sharedMyIdentityStore].pushFromName.length > 0) {
  220. self.nickNameLabel.text = [MyIdentityStore sharedMyIdentityStore].pushFromName;
  221. self.nickNameLabel.accessibilityLabel = [NSString stringWithFormat:@"%@: %@", NSLocalizedString(@"id_completed_nickname", @""), [MyIdentityStore sharedMyIdentityStore].pushFromName];
  222. } else {
  223. self.nickNameLabel.text = [MyIdentityStore sharedMyIdentityStore].identity;
  224. self.nickNameLabel.accessibilityLabel = [NSString stringWithFormat:@"%@: %@", NSLocalizedString(@"id_completed_nickname", @""), [MyIdentityStore sharedMyIdentityStore].identity];
  225. }
  226. }
  227. - (void)updateProfilePicture {
  228. NSData *profilePicture = [[MyIdentityStore sharedMyIdentityStore] profilePicture][@"ProfilePicture"];
  229. if (profilePicture) {
  230. _imageView.image = [UIImage imageWithData:profilePicture];
  231. _imageView.contentMode = UIViewContentModeScaleAspectFill;
  232. _imageView.layer.masksToBounds = YES;
  233. _imageView.layer.cornerRadius = _imageView.bounds.size.width / 2;
  234. } else {
  235. _imageView.image = [[AvatarMaker sharedAvatarMaker] unknownPersonImage];
  236. }
  237. _imageView.accessibilityLabel = NSLocalizedString(@"my_profilepicture", @"");
  238. }
  239. - (void)updateColors {
  240. nickNameTitleLabel.textColor = [Colors fontVeryLight];
  241. nickNameTitleLabel.shadowColor = nil;
  242. threemaIdTitleLabel.textColor = [Colors fontVeryLight];
  243. threemaIdTitleLabel.shadowColor = nil;
  244. nickNameLabel.textColor = [Colors fontNormal];
  245. nickNameLabel.shadowColor = nil;
  246. threemaIdLabel.textColor = [Colors fontNormal];
  247. threemaIdLabel.shadowColor = nil;
  248. UIImage *editImage = [self.editButton.imageView.image imageWithTint:[Colors main]];
  249. [self.editButton setImage:editImage forState:UIControlStateNormal];
  250. UIImage *shareIdImage = [self.shareIdButton.imageView.image imageWithTint:[Colors main]];
  251. [self.shareIdButton setImage:shareIdImage forState:UIControlStateNormal];
  252. UIColor *qrBackgroundColor;
  253. if ([Colors getTheme] == ColorThemeDark || [Colors getTheme] == ColorThemeDarkWork) {
  254. qrBackgroundColor = [Colors chatBarBackground];
  255. } else {
  256. qrBackgroundColor = [Colors fontInverted];
  257. }
  258. UIImage *qrBackgroundImage = [self.qrBackgroundImageView.image imageWithTint:qrBackgroundColor];
  259. qrBackgroundImageView.image = qrBackgroundImage;
  260. UIImage *qrCodeImage = self.qrCodeButton.imageView.image;
  261. switch ([Colors getTheme]) {
  262. case ColorThemeDark:
  263. case ColorThemeDarkWork:
  264. qrCodeImage = [qrCodeImage imageWithTint:[UIColor whiteColor]];
  265. break;
  266. default:
  267. qrCodeImage = [qrCodeImage imageWithTint:[UIColor blackColor]];
  268. break;
  269. }
  270. [self.qrCodeButton setImage:qrCodeImage forState:UIControlStateNormal];
  271. }
  272. - (void)updateThreemaSafe {
  273. SafeConfigManager *safeConfigManager = [[SafeConfigManager alloc] init];
  274. SafeStore *safeStore = [[SafeStore alloc] initWithSafeConfigManagerAsObject:safeConfigManager serverApiConnector:[[ServerAPIConnector alloc] init]];
  275. SafeManager *safeManager = [[SafeManager alloc] initWithSafeConfigManagerAsObject:safeConfigManager safeStore:safeStore safeApiService:[[SafeApiService alloc] init]];
  276. if ([safeManager isActivated]) {
  277. self.threemaSafeLabel.text = [BundleUtil localizedStringForKey:@"On"];
  278. } else {
  279. self.threemaSafeLabel.text = [BundleUtil localizedStringForKey:@"Off"];
  280. }
  281. }
  282. - (void)triggerRevocationKeyCheck {
  283. [_revocationKeyHandler updateLastSetDateForLabel:_revocationLabelDetail];
  284. }
  285. - (void)fullScreenQrCodeTapped:(UITapGestureRecognizer *)sender {
  286. if (sender.state == UIGestureRecognizerStateEnded) {
  287. [self hideFullScreenQrViewAnimated:YES];
  288. }
  289. }
  290. - (void)showFullScreenQrView {
  291. /* QR code */
  292. qrRect = _qrCodeButton.frame;
  293. qrZoomedRect = [_qrCodeButton.superview convertRect:qrRect toView:self.view.superview];
  294. /* Center in view with margin */
  295. CGRect contentRect = self.view.superview.frame;
  296. int maxw = contentRect.size.width - 40;
  297. int maxh = contentRect.size.height - 40;
  298. int dim = MIN(maxw, maxh);
  299. CGRect qrZoomedTargetRect = CGRectMake((contentRect.size.width - dim) / 2, (contentRect.size.height - dim) / 2, dim, dim);
  300. coverView = [[UIView alloc] initWithFrame:self.view.frame];
  301. coverView.alpha = 0.0;
  302. coverView.backgroundColor = [UIColor whiteColor];
  303. coverView.accessibilityLabel = @"CoverView";
  304. zoomingQrImageView = [[UIImageView alloc] initWithFrame:qrZoomedRect];
  305. zoomingQrImageView.image = [self renderQrCodeWithDimension:self.view.frame.size.width * [UIScreen mainScreen].scale];
  306. zoomingQrImageView.alpha = 0.0;
  307. zoomingQrImageView.accessibilityLabel = @"Big qr code";
  308. [coverView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(fullScreenQrCodeTapped:)]];
  309. [self.view.superview addSubview:coverView];
  310. [self.view.superview addSubview:zoomingQrImageView];
  311. [UIView animateWithDuration:0.5 animations:^{
  312. coverView.alpha = 1.0;
  313. zoomingQrImageView.frame = qrZoomedTargetRect;
  314. zoomingQrImageView.alpha = 1.0;
  315. }];
  316. }
  317. - (void)hideFullScreenQrViewAnimated:(BOOL)animated {
  318. if (coverView == nil)
  319. return;
  320. if (animated) {
  321. [UIView animateWithDuration:0.5 animations:^{
  322. coverView.alpha = 0.0;
  323. zoomingQrImageView.frame = qrZoomedRect;
  324. zoomingQrImageView.alpha = 0.0;
  325. } completion:^(BOOL finished) {
  326. [coverView removeFromSuperview];
  327. [zoomingQrImageView removeFromSuperview];
  328. coverView = nil;
  329. zoomingQrImageView = nil;
  330. }];
  331. } else {
  332. [coverView removeFromSuperview];
  333. [zoomingQrImageView removeFromSuperview];
  334. coverView = nil;
  335. zoomingQrImageView = nil;
  336. }
  337. }
  338. - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
  339. [self hideFullScreenQrViewAnimated:NO];
  340. }
  341. - (void)createBackup {
  342. CreatePasswordTrigger *passwordTrigger = [CreatePasswordTrigger createPasswordTriggerOn: self];
  343. passwordTrigger.passwordCallback = self;
  344. passwordTrigger.passwordAdditionalText = NSLocalizedString(@"password_description_backup", nil);
  345. [passwordTrigger presentPasswordUI];
  346. }
  347. - (void)createRevocationKey {
  348. CreatePasswordTrigger *passwordTrigger = [CreatePasswordTrigger createPasswordTriggerOn: self];
  349. passwordTrigger.passwordCallback = _revocationKeyHandler;
  350. passwordTrigger.passwordTitle = NSLocalizedString(@"revocation_password", nil);
  351. passwordTrigger.passwordAdditionalText = NSLocalizedString(@"revocation_password_description", nil);
  352. [passwordTrigger presentPasswordUI];
  353. }
  354. - (void)scrollToLinkSection {
  355. [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:1] atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
  356. }
  357. - (void)startSetPublicNickname {
  358. [self performSegueWithIdentifier:SEGUE_NICKNAME sender:self];
  359. }
  360. - (void)showSafeSetup {
  361. [self performSegueWithIdentifier:SEGUE_SAFE_SETUP sender:self];
  362. }
  363. - (UIImage*)renderQrCodeWithDimension:(int)dimension {
  364. MyIdentityStore *myIdentityStore = [MyIdentityStore sharedMyIdentityStore];
  365. if (!myIdentityStore.isProvisioned) {
  366. return nil;
  367. }
  368. NSMutableString *qrString = [NSMutableString stringWithString:@"3mid:"];
  369. [qrString appendString:myIdentityStore.identity];
  370. [qrString appendString:@","];
  371. [qrString appendString:[NSString stringWithHexData:myIdentityStore.publicKey]];
  372. return [QRCodeGenerator renderQrCodeString:qrString withDimension:dimension];
  373. }
  374. - (void)disabledCellsForMDM {
  375. // isReadonlyProfile
  376. self.linkEmailCell.userInteractionEnabled = ![mdmSetup readonlyProfile];
  377. self.linkEmailCell.textLabel.enabled = ![mdmSetup readonlyProfile];
  378. self.linkPhoneCell.userInteractionEnabled = ![mdmSetup readonlyProfile];
  379. self.linkPhoneCell.textLabel.enabled = ![mdmSetup readonlyProfile];
  380. self.idRecoveryCell.userInteractionEnabled = ![mdmSetup readonlyProfile];
  381. self.idRecoveryCell.textLabel.enabled = ![mdmSetup readonlyProfile];
  382. self.deleteIdCell.userInteractionEnabled = ![mdmSetup readonlyProfile];
  383. self.deleteIdCell.textLabel.enabled = ![mdmSetup readonlyProfile];
  384. self.deleteIdCell.textLabel.text = [BundleUtil localizedStringForKey:@"delete_identity"];
  385. // disableBackups
  386. self.backupCell.userInteractionEnabled = !(mdmSetup.disableBackups || mdmSetup.disableIdExport);
  387. self.backupCell.textLabel.enabled = !(mdmSetup.disableBackups || mdmSetup.disableIdExport);
  388. self.threemaSafeCell.userInteractionEnabled = ![mdmSetup isSafeBackupDisable];
  389. self.threemaSafeCell.textLabel.enabled = ![mdmSetup isSafeBackupDisable];
  390. }
  391. - (void)tappedHeaderView {
  392. [self performSegueWithIdentifier:@"EditProfile" sender:nil];
  393. }
  394. - (void)tappedShareThreemaId {
  395. NSString *threemaShareText = [BundleUtil localizedStringForKey:@"profile_share_id_text"];
  396. NSString *threemaShareLink = [NSString stringWithFormat:@"%@: %@%@", threemaShareText, THREEMA_ID_SHARE_LINK, [[MyIdentityStore sharedMyIdentityStore] identity]];
  397. UIActivityViewController *activityViewController = [ActivityUtil activityViewControllerWithActivityItems:@[threemaShareLink] applicationActivities:nil];
  398. if (SYSTEM_IS_IPAD == YES) {
  399. activityViewController.popoverPresentationController.sourceRect = _shareIdButton.frame;
  400. activityViewController.popoverPresentationController.sourceView = self.view;
  401. }
  402. [self presentViewController:activityViewController animated:YES completion:nil];
  403. }
  404. #pragma mark - Table view delegate
  405. - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
  406. if (indexPath.section == 3 && indexPath.row == 0) {
  407. // handle custom table cells
  408. [Colors updateTableViewCellBackground:cell];
  409. [Colors setTextColor:[Colors red] inView:cell.contentView];
  410. } else {
  411. [Colors updateTableViewCell:cell];
  412. }
  413. if (indexPath.section == 0) {
  414. self.keyFingerprintLabel.textColor = [Colors fontLight];
  415. }
  416. }
  417. - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
  418. if (section == 0 && ![mdmSetup readonlyProfile] && ![mdmSetup disableBackups] && [mdmSetup disableAddContact]) {
  419. return NSLocalizedString(@"disabled_by_device_policy", nil);
  420. }
  421. else if (section == 1) {
  422. return NSLocalizedString(![mdmSetup isSafeBackupDisable] ? @"safe_enable_explain_short" : @"disabled_by_device_policy", nil);
  423. }
  424. else if (section == 2 && ([mdmSetup readonlyProfile] || [mdmSetup disableBackups] || [mdmSetup disableIdExport])) {
  425. return NSLocalizedString(@"disabled_by_device_policy", nil);
  426. }
  427. return nil;
  428. }
  429. - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
  430. if (section == 0) {
  431. return 0.0;
  432. }
  433. return UITableViewAutomaticDimension;
  434. }
  435. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
  436. {
  437. if (indexPath.section == 0 && indexPath.row == 0) {
  438. /* Link mobile no */
  439. if ([MyIdentityStore sharedMyIdentityStore].linkMobileNoPending)
  440. [self performSegueWithIdentifier:@"EnterCode" sender:self];
  441. else
  442. [self performSegueWithIdentifier:@"LinkMobileNo" sender:self];
  443. } else if (indexPath.section == 2 && indexPath.row == 1) {
  444. [self createBackup];
  445. } else if (indexPath.section == 2 && indexPath.row == 2) {
  446. [self createRevocationKey];
  447. } else if (indexPath.section == 3 && indexPath.row == 0) {
  448. UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
  449. [self deleteIdentity:cell];
  450. }
  451. [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
  452. }
  453. - (IBAction)deleteIdentity:(id)sender {
  454. if ([KKPasscodeLock sharedLock].isPasscodeRequired) {
  455. [UIAlertTemplate showAlertWithOwner:self title:NSLocalizedString(@"delete_identity_passcode_title", nil) message:NSLocalizedString(@"delete_identity_passcode_message", nil) actionOk:nil];
  456. return;
  457. }
  458. deleteActionSheet = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"delete_identity_warning", nil) message:nil preferredStyle:UIAlertControllerStyleActionSheet];
  459. [deleteActionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"delete_identity", nil) style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) {
  460. UIAlertController *alert = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"delete_identity", nil) message:NSLocalizedString(@"delete_identity_warning2", nil) preferredStyle:UIAlertControllerStyleAlert];
  461. [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"cancel", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) {
  462. }]];
  463. [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"delete_identity", nil) style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) {
  464. /* they wanted it that way... */
  465. [[MyIdentityStore sharedMyIdentityStore] destroy];
  466. SafeConfigManager *safeConfigManager = [[SafeConfigManager alloc] init];
  467. [safeConfigManager destroy];
  468. SafeStore *safeStore = [[SafeStore alloc] initWithSafeConfigManagerAsObject:safeConfigManager serverApiConnector:[[ServerAPIConnector alloc] init]];
  469. SafeManager *safeManager = [[SafeManager alloc] initWithSafeConfigManagerAsObject:safeConfigManager safeStore:safeStore safeApiService:[[SafeApiService alloc] init]];
  470. [safeManager setBackupReminder];
  471. if ([LicenseStore requiresLicenseKey]) {
  472. // Delete the license when we delete the ID, to give the user a chance to use a new license.
  473. // The license may have been supplied by MDM, so we load it again.
  474. [[LicenseStore sharedLicenseStore] deleteLicense];
  475. [mdmSetup loadLicenseInfo];
  476. if ([LicenseStore sharedLicenseStore].licenseUsername == nil || [LicenseStore sharedLicenseStore].licensePassword == nil)
  477. [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationLicenseMissing object:nil];
  478. [mdmSetup deleteThreemaMdm];
  479. }
  480. // Show information about delete all data
  481. UIStoryboard *storyboard = [AppDelegate getMyIdentityStoryboard];
  482. UIViewController *deleteIdViewControiller = [storyboard instantiateViewControllerWithIdentifier:@"DeleteIdViewController"];
  483. deleteIdViewControiller.modalPresentationStyle = UIModalPresentationFullScreen;
  484. [self presentViewController:deleteIdViewControiller animated:YES completion:nil];
  485. }]];
  486. [self presentViewController:alert animated:YES completion:nil];
  487. }]];
  488. [deleteActionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"cancel", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) {
  489. }]];
  490. if ([sender isKindOfClass:[UIView class]]) {
  491. UIView *senderView = (UIView *)sender;
  492. deleteActionSheet.popoverPresentationController.sourceRect = senderView.frame;
  493. deleteActionSheet.popoverPresentationController.sourceView = self.view;
  494. }
  495. [self presentViewController:deleteActionSheet animated:YES completion:nil];
  496. }
  497. - (IBAction)scanIdentity:(id)sender {
  498. if ([mdmSetup disableAddContact]) {
  499. [UIAlertTemplate showAlertWithOwner:self title:@"" message:NSLocalizedString(@"disabled_by_device_policy", nil) actionOk:nil];
  500. return;
  501. }
  502. ScanIdentityController *scanIdentityController = [[ScanIdentityController alloc] init];
  503. scanIdentityController.containingViewController = self;
  504. [scanIdentityController startScan];
  505. /* a good opportunity to sync contacts - maybe we find the contact
  506. that the user is about to scan */
  507. [[ContactStore sharedContactStore] synchronizeAddressBookForceFullSync:YES onCompletion:nil onError:nil];
  508. }
  509. #pragma mark - PasswordCallback
  510. -(void)passwordResult:(NSString *)password fromViewController:(UIViewController *)viewController {
  511. [MBProgressHUD showHUDAddedTo:viewController.view animated:YES];
  512. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  513. NSString *backupData = [[MyIdentityStore sharedMyIdentityStore] backupIdentityWithPassword:password];
  514. dispatch_async(dispatch_get_main_queue(), ^{
  515. [MBProgressHUD hideHUDForView:viewController.view animated:YES];
  516. UIStoryboard *storyboard = [AppDelegate getMainStoryboard];
  517. BackupIdentityViewController *idVc = [storyboard instantiateViewControllerWithIdentifier: @"BackupIdentityViewController"];
  518. idVc.backupData = backupData;
  519. [viewController.navigationController pushViewController:idVc animated:YES];
  520. });
  521. });
  522. }
  523. #pragma mark - UIScrollViewDelegate
  524. - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
  525. if (![LicenseStore requiresLicenseKey]) {
  526. if ([[self.navigationController navigationBar] frame].size.height < 60.0 && self.navigationItem.titleView != nil) {
  527. self.navigationItem.titleView = nil;
  528. self.navigationItem.title = [BundleUtil localizedStringForKey:@"myIdentity"];
  529. }
  530. else if ([[self.navigationController navigationBar] frame].size.height >= 59.5 && self.navigationItem.titleView == nil) {
  531. [BrandingUtils updateTitleLogoOfNavigationItem:self.navigationItem navigationController:self.navigationController];
  532. }
  533. }
  534. }
  535. - (void)willDismissModalNavigationController {
  536. [self updateView];
  537. }
  538. @end