merge default IOS-1756
authorXavier Algarra <xavier@pep-project.org>
Fri, 07 Feb 2020 12:31:01 +0100
branchIOS-1756
changeset 1166329c60f41f881
parent 11662 7d63d4273cd2
parent 11654 c175704156ef
child 11665 2fafad095006
merge default
pEpForiOS.xcodeproj/project.pbxproj
pEpForiOS/Base.lproj/AccountCreation.storyboard
pEpForiOS/UI/Folder/FolderTableViewController.swift
     1.1 --- a/.hgtags	Fri Feb 07 12:29:26 2020 +0100
     1.2 +++ b/.hgtags	Fri Feb 07 12:31:01 2020 +0100
     1.3 @@ -70,3 +70,5 @@
     1.4  279e59c37cc5fd62ee534a9c17e2f5292e9f32fa v1.0.903
     1.5  c559355aedc24d244f926ee8ae681f1331e8c306 v1.0.904
     1.6  b48fed65c2bd08e510edc9948ebf7009e6ea87a0 v1.0.905
     1.7 +8e4e9e05ac94b6ceb8e48d8e43ca861567a36ec7 v1.0.908
     1.8 +d1d314d801cb41fde410eb782cbd37e5b0df72f5 v1.0.909
     2.1 --- a/CHANGESETS	Fri Feb 07 12:29:26 2020 +0100
     2.2 +++ b/CHANGESETS	Fri Feb 07 12:31:01 2020 +0100
     2.3 @@ -1,19 +1,15 @@
     2.4  v$(MARKETING_VERSION)
     2.5  AppAuth-iOS: c9103384853af90b046219573f322286de306564
     2.6 -MessageModel: 2f6128c8c393
     2.7 +MessageModel: 937b429b0a39
     2.8  OpenSSL-for-iPhone: 10019638e80e8a8a5fc19642a840d8a69fac7349
     2.9  SwipeCellKit: 00cd0cb5f9ceb4ae7a245fe21bf45643285d454b
    2.10 -_Catalyst_OpenSSL-for-iPhone: 3281c22e0e98571e5f4c0731d203edbae972d43f
    2.11 -_Catalyst_sequoia4ios: 222394513b40473a677ef59fb2da3fbeda75be85
    2.12  ldns: e83e808f0c56f6235061f5c904ff476ca75aa576
    2.13  libAccountSettings: 23e0aedaf6a7
    2.14  libetpan: c76daba0153eed0003d6990a5adadba8d561b8fa
    2.15 -pEp-Translate: 0a038f72b49184ad37f0b4931730391ee59ca097
    2.16 -pEpEngine: 1e909e9a4548
    2.17 -pEpObjCAdapter: adbedc09b0fe
    2.18 -pEp_for_iOS: 5398a0a9b611+
    2.19 +pEp-Translate: 3c45a41fdb1634881442d8534782b1416266f64c
    2.20 +pEpEngine: f2ee5ebb0c67
    2.21 +pEpObjCAdapter: f447f6f20248
    2.22 +pEp_for_iOS: 41fa713b5ee8+
    2.23  pEp_for_iOS_intern: fe7c80780efc+
    2.24 -pantomime-iOS: c7831357cede+
    2.25 -pep4applemail: 4834dd822a00419a61ec6d56018f1685fa430a18
    2.26 -sequoia4ios: 222394513b40473a677ef59fb2da3fbeda75be85
    2.27 -sequoia4macos: c14da7a342ea6721a7f82623072b915c0abf16da
    2.28 +pantomime-iOS: 93b3edc1db59
    2.29 +sequoia4ios: 3b4b432400c9827ecaf2f7a185333ea1488f4e5c
     3.1 Binary file Design/icons/chevron-icon-down.pdf has changed
     4.1 Binary file Design/icons/chevron-icon-left.pdf has changed
     5.1 Binary file Design/icons/chevron-icon-right.pdf has changed
     6.1 Binary file Design/icons/chevron-icon-up.pdf has changed
     7.1 Binary file Design/icons/pEpForiOS-icon-mistrusted.pdf has changed
     8.1 Binary file Design/icons/pEpForiOS-icon-secure&trusted.pdf has changed
     9.1 Binary file Design/icons/pEpForiOS-icon-secure.pdf has changed
    10.1 Binary file Design/icons/pEpForiOS-icon-settings.pdf has changed
    11.1 Binary file Design/icons/pep-status-mistrusted-english.pdf has changed
    12.1 Binary file Design/icons/pep-status-secure&trusted-disabled-english.pdf has changed
    13.1 Binary file Design/icons/pep-status-secure&trusted-english.pdf has changed
    14.1 Binary file Design/icons/pep-status-secure-disabled-english.pdf has changed
    15.1 Binary file Design/icons/pep-status-secure-english.pdf has changed
    16.1 Binary file Design/icons/pep-status-underattack-english.pdf has changed
    17.1 --- a/README.md	Fri Feb 07 12:29:26 2020 +0100
    17.2 +++ b/README.md	Fri Feb 07 12:31:01 2020 +0100
    17.3 @@ -14,23 +14,23 @@
    17.4  For building the engine, you need a working python3 environment and all dependencies:
    17.5  
    17.6  ```
    17.7 +sudo port install git
    17.8 +sudo port install mercurial
    17.9 +
   17.10  sudo port install asn1c
   17.11  
   17.12 -sudo port install python27
   17.13  sudo port install python38
   17.14  sudo port install py38-lxml
   17.15 -sudo port select --set python python27
   17.16  sudo port select --set python3 python38
   17.17  
   17.18 -sudo port install mercurial
   17.19 -
   17.20 +sudo port install gmake
   17.21  sudo port install autoconf
   17.22  sudo port install libtool
   17.23  sudo port install automake
   17.24  
   17.25 -sudo port install gmake
   17.26 +sudo port install wget
   17.27  
   17.28 -sudo port install wget
   17.29 +sudo port install capnproto
   17.30  
   17.31  curl https://sh.rustup.rs -sSf | sh
   17.32  
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/Submodules/pEpIOSToolbox/pEpIOSToolbox/UIKit/UIView+Autolayout.swift	Fri Feb 07 12:31:01 2020 +0100
    18.3 @@ -0,0 +1,31 @@
    18.4 +//
    18.5 +//  UIView+Autolayout.swift
    18.6 +//  pEp
    18.7 +//
    18.8 +//  Created by Andreas Buff on 09.03.18.
    18.9 +//  Copyright © 2018 p≡p Security S.A. All rights reserved.
   18.10 +//
   18.11 +
   18.12 +import UIKit
   18.13 +
   18.14 +extension UIView {
   18.15 +    /// Sets up constraints to always stay the same size as the superview.
   18.16 +    public func fullSizeInSuperView() {
   18.17 +        guard let superview = self.superview else {
   18.18 +            Log.shared.errorAndCrash("No superview")
   18.19 +            return
   18.20 +        }
   18.21 +
   18.22 +        self.translatesAutoresizingMaskIntoConstraints = false
   18.23 +        superview.addConstraints(NSLayoutConstraint.constraints(
   18.24 +            withVisualFormat: "H:|-0-[subview]-0-|",
   18.25 +            options: .directionLeadingToTrailing,
   18.26 +            metrics: nil,
   18.27 +            views: ["subview": self]))
   18.28 +        superview.addConstraints(NSLayoutConstraint.constraints(
   18.29 +            withVisualFormat: "V:|-0-[subview]-0-|",
   18.30 +            options: .directionLeadingToTrailing,
   18.31 +            metrics: nil,
   18.32 +            views: ["subview": self]))
   18.33 +    }
   18.34 +}
    19.1 --- a/pEpForiOS.xcodeproj/project.pbxproj	Fri Feb 07 12:29:26 2020 +0100
    19.2 +++ b/pEpForiOS.xcodeproj/project.pbxproj	Fri Feb 07 12:31:01 2020 +0100
    19.3 @@ -25,7 +25,6 @@
    19.4  		004422CA2179ECD600BDF6DF /* PassiveModeViewModelTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 004422C92179ECD600BDF6DF /* PassiveModeViewModelTest.swift */; };
    19.5  		004422D9217A25AD00BDF6DF /* UnencryptedSubjectViewModelTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 004422D8217A25AD00BDF6DF /* UnencryptedSubjectViewModelTest.swift */; };
    19.6  		005A21FB20CAA5F50082D19F /* ThreadedEmailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 005A21FA20CAA5F50082D19F /* ThreadedEmailViewModel.swift */; };
    19.7 -		0069DCFB2110679200846EB1 /* EmailViewController+UIPopoverPresentationControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0069DCFA2110679200846EB1 /* EmailViewController+UIPopoverPresentationControllerDelegate.swift */; };
    19.8  		006BE6BC20F4B63C00DDE8C9 /* EmailDetailType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 006BE6BB20F4B63C00DDE8C9 /* EmailDetailType.swift */; };
    19.9  		00A12CAE20D3D9AC00B82BE3 /* FullMessageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00A12CAD20D3D9AC00B82BE3 /* FullMessageCell.swift */; };
   19.10  		00AEB2F620DBA7DA00DA185A /* NeedsRefreshDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00AEB2F520DBA7DA00DA185A /* NeedsRefreshDelegate.swift */; };
   19.11 @@ -36,7 +35,6 @@
   19.12  		00EB89AD20E3D3C200CDFA0D /* ThreadedEmailViewModel+MoveToFolderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00EB89AC20E3D3C200CDFA0D /* ThreadedEmailViewModel+MoveToFolderDelegate.swift */; };
   19.13  		00EB89AF20E3E4A000CDFA0D /* ReplyAlertCreator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00EB89AE20E3E4A000CDFA0D /* ReplyAlertCreator.swift */; };
   19.14  		00FD0CE62101F7D700BA0C56 /* ScreenComposerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00FD0CE52101F7D700BA0C56 /* ScreenComposerProtocol.swift */; };
   19.15 -		00FD0CE82102014C00BA0C56 /* PrimarySplitViewcontroller+ScreenComposerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00FD0CE72102014C00BA0C56 /* PrimarySplitViewcontroller+ScreenComposerProtocol.swift */; };
   19.16  		150707DC21006CD000AA213F /* ComposeUtilTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 150707DB21006CD000AA213F /* ComposeUtilTest.swift */; };
   19.17  		150B8E991FCDACBB00374438 /* AccountSettingsUserInputError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 150B8E971FCDACBB00374438 /* AccountSettingsUserInputError.swift */; };
   19.18  		150B8EB31FCEB93D00374438 /* UIUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 150B8EB21FCEB93D00374438 /* UIUtils.swift */; };
   19.19 @@ -161,6 +159,9 @@
   19.20  		15874BD22127493E00A3A4A6 /* TrustedServerSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15874BC02127493E00A3A4A6 /* TrustedServerSettingsViewController.swift */; };
   19.21  		15874BD421274BD400A3A4A6 /* TrustedServerSettingCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15874BD321274BD400A3A4A6 /* TrustedServerSettingCell.swift */; };
   19.22  		158A6E2F230D53E3006A9ECE /* ExtraKeysSettingViewModelTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 158A6E2E230D53E3006A9ECE /* ExtraKeysSettingViewModelTest.swift */; };
   19.23 +		15944A30239802D5006B133B /* EmailDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15944A2F239802D5006B133B /* EmailDetailViewController.swift */; };
   19.24 +		15944A3223980C99006B133B /* EmailDetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15944A3123980C99006B133B /* EmailDetailViewModel.swift */; };
   19.25 +		15944A3523980FEC006B133B /* EmailDisplayViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15944A3423980FEC006B133B /* EmailDisplayViewModel.swift */; };
   19.26  		159AB56D23539D67008AB1F3 /* AppSettings+CNContactsAccessPermissionProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 159AB56C23539D67008AB1F3 /* AppSettings+CNContactsAccessPermissionProvider.swift */; };
   19.27  		159E1F1322BD074F007D711F /* PantomimeFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 159E1F1222BD074F007D711F /* PantomimeFramework.framework */; };
   19.28  		159E1F1522BD0756007D711F /* PEPObjCAdapterFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 159E1F1422BD0756007D711F /* PEPObjCAdapterFramework.framework */; };
   19.29 @@ -172,6 +173,8 @@
   19.30  		15BA536E20A095410090F126 /* UnifiedInboxTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15BA536D20A095410090F126 /* UnifiedInboxTest.swift */; };
   19.31  		15BBBC6B1FD0527200B9DCC8 /* DisplayUserErrorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15BBBC6A1FD0527200B9DCC8 /* DisplayUserErrorTest.swift */; };
   19.32  		15BBBC6C1FD05F4300B9DCC8 /* DisplayUserError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 152130531FD00B7A00688DF2 /* DisplayUserError.swift */; };
   19.33 +		15D3D48B239FC14700F2EBFB /* EmailDetailCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15D3D489239FC14700F2EBFB /* EmailDetailCollectionViewCell.swift */; };
   19.34 +		15D3D48C239FC14700F2EBFB /* EmailDetailCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 15D3D48A239FC14700F2EBFB /* EmailDetailCollectionViewCell.xib */; };
   19.35  		15D4399A216E697700EB3933 /* AccountPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15D43999216E697700EB3933 /* AccountPickerView.swift */; };
   19.36  		15D4399C216E698E00EB3933 /* AccountPickerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15D4399B216E698E00EB3933 /* AccountPickerViewModel.swift */; };
   19.37  		15D439A5216F7E0E00EB3933 /* AccountPickerViewModelTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15D439A4216F7E0E00EB3933 /* AccountPickerViewModelTest.swift */; };
   19.38 @@ -213,6 +216,7 @@
   19.39  		371D6420231D17F80036AE62 /* TutorialWizardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371D641F231D17F80036AE62 /* TutorialWizardViewController.swift */; };
   19.40  		3756434E2370810400FB354D /* EditableAccountSettingsViewModelTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F272EF237075D9005C51AA /* EditableAccountSettingsViewModelTest.swift */; };
   19.41  		375643502371BC4600FB354D /* EditableAccountSettingsTableViewModelTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3756434F2371B92200FB354D /* EditableAccountSettingsTableViewModelTest.swift */; };
   19.42 +		375BA08A238BFC4100BBFE7C /* ManualAccountSetupContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 375BA089238BFC4100BBFE7C /* ManualAccountSetupContainerView.swift */; };
   19.43  		37816542230EC72C00B967E3 /* PEPAlertViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37816541230EC72C00B967E3 /* PEPAlertViewController.swift */; };
   19.44  		37816544230EC73900B967E3 /* PEPAlertViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37816543230EC73900B967E3 /* PEPAlertViewModel.swift */; };
   19.45  		37816546230EE5F700B967E3 /* PEPUIAlertAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37816545230EE5F700B967E3 /* PEPUIAlertAction.swift */; };
   19.46 @@ -220,6 +224,10 @@
   19.47  		3791A46122BA77C900A9E534 /* KeySyncServiceHandshakeDelegateMoc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3791A46022BA77C900A9E534 /* KeySyncServiceHandshakeDelegateMoc.swift */; };
   19.48  		37A710E0233B5AA5001FEAF0 /* UIHelper+PEP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A710DF233B5AA5001FEAF0 /* UIHelper+PEP.swift */; };
   19.49  		37C3C0E62260C64D003E290C /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37C3C0E52260C64D003E290C /* Log.swift */; };
   19.50 +		37F615C92386B14A001AAE48 /* LoginScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F615C82386B14A001AAE48 /* LoginScrollView.swift */; };
   19.51 +		37F615CC238BE51F001AAE48 /* ManualAccountSetupView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 37F615CB238BE51F001AAE48 /* ManualAccountSetupView.xib */; };
   19.52 +		37F615CF238BE584001AAE48 /* ManualAccountSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F615CE238BE584001AAE48 /* ManualAccountSetupView.swift */; };
   19.53 +		37FFA7FA234B3C27004229BE /* AnimatedPlaceholderTextfield.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37FFA7F9234B3C27004229BE /* AnimatedPlaceholderTextfield.swift */; };
   19.54  		43040A531E9776220083DED8 /* AttachmentSummaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43040A521E9776220083DED8 /* AttachmentSummaryView.swift */; };
   19.55  		4304FD001EBB8EBB0086DADA /* LanguageListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4304FCFE1EBB8C5A0086DADA /* LanguageListViewController.swift */; };
   19.56  		4307D5DA23575853004569C4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4307D5D823575853004569C4 /* InfoPlist.strings */; };
   19.57 @@ -364,10 +372,9 @@
   19.58  		43EC75B32164E97800048CFE /* DecryptionUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43EC75B22164E97800048CFE /* DecryptionUtil.swift */; };
   19.59  		43ED536F1CC77F95006AB156 /* EmailListViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43ED53631CC77F95006AB156 /* EmailListViewCell.swift */; };
   19.60  		43ED53701CC77F95006AB156 /* EmailListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43ED53641CC77F95006AB156 /* EmailListViewController.swift */; };
   19.61 -		43ED53711CC77F95006AB156 /* IMAPSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43ED53661CC77F95006AB156 /* IMAPSettingsTableViewController.swift */; };
   19.62 -		43ED53771CC77F95006AB156 /* OneValueSettingCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43ED536C1CC77F95006AB156 /* OneValueSettingCell.swift */; };
   19.63 -		43ED53781CC77F95006AB156 /* SMTPSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43ED536D1CC77F95006AB156 /* SMTPSettingsTableViewController.swift */; };
   19.64 -		43ED53791CC77F95006AB156 /* UserInfoTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43ED536E1CC77F95006AB156 /* UserInfoTableViewController.swift */; };
   19.65 +		43ED53711CC77F95006AB156 /* IMAPSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43ED53661CC77F95006AB156 /* IMAPSettingsViewController.swift */; };
   19.66 +		43ED53781CC77F95006AB156 /* SMTPSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43ED536D1CC77F95006AB156 /* SMTPSettingsViewController.swift */; };
   19.67 +		43ED53791CC77F95006AB156 /* UserInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43ED536E1CC77F95006AB156 /* UserInfoViewController.swift */; };
   19.68  		43F7F07A1F6AD44600BDF151 /* HandshakeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43F7F0791F6AD44600BDF151 /* HandshakeTests.swift */; };
   19.69  		43F7F07C1F6AD4FD00BDF151 /* HandshakeTests_mail_001.txt in Resources */ = {isa = PBXBuildFile; fileRef = 43F7F07B1F6AD4FD00BDF151 /* HandshakeTests_mail_001.txt */; };
   19.70  		43F9D99A1E92725700F78A1C /* AttachmentsViewHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43F9D9991E92725700F78A1C /* AttachmentsViewHelper.swift */; };
   19.71 @@ -375,7 +382,6 @@
   19.72  		43FE8030209995AD00E97AB3 /* QualifyServerIsLocalServiceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FE802F209995AD00E97AB3 /* QualifyServerIsLocalServiceTest.swift */; };
   19.73  		4902244F20E50488000E8D7C /* ThreadNavigationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4902244E20E50488000E8D7C /* ThreadNavigationDelegate.swift */; };
   19.74  		490CEBA72100EAD500E8579C /* SelfDismissable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 490CEBA62100EAD500E8579C /* SelfDismissable.swift */; };
   19.75 -		490CEBA921020BF900E8579C /* LoginViewController+Keyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 490CEBA821020BF900E8579C /* LoginViewController+Keyboard.swift */; };
   19.76  		491116BD216E0DF4005A42D2 /* MessageViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491116BC216E0DF4005A42D2 /* MessageViewModelTests.swift */; };
   19.77  		4918EBFC1E783C70006207FC /* CdMessage+PantomimeTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4918EBFA1E783C70006207FC /* CdMessage+PantomimeTest.swift */; };
   19.78  		491B656220CFE0FD00C2ADDA /* Thread.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 491B656020CFE0FD00C2ADDA /* Thread.storyboard */; };
   19.79 @@ -384,7 +390,6 @@
   19.80  		492EF92D20C6957D004EAE14 /* ThreadViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 492EF92C20C6957D004EAE14 /* ThreadViewController.swift */; };
   19.81  		492EF92F20C699D0004EAE14 /* ThreadViewController+TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 492EF92E20C699D0004EAE14 /* ThreadViewController+TableView.swift */; };
   19.82  		495D69BF20DBAEE900986007 /* ThreadViewController+SwipeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 495D69BE20DBAEE900986007 /* ThreadViewController+SwipeCell.swift */; };
   19.83 -		495F607C20B564CD00F47BD6 /* EmailViewController+SizeClasses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 495F607B20B564CD00F47BD6 /* EmailViewController+SizeClasses.swift */; };
   19.84  		496355B120ECEA2900AA4387 /* ThreadedEmailViewModel+EmailDisplayDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 496355B020ECEA2900AA4387 /* ThreadedEmailViewModel+EmailDisplayDelegate.swift */; };
   19.85  		49691B1520D7FD0200CA9367 /* MessageViewModelConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49691B1420D7FD0200CA9367 /* MessageViewModelConfigurable.swift */; };
   19.86  		49A6114E2179F3A1006BA3C5 /* UnitTestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49A6114D2179F3A1006BA3C5 /* UnitTestUtils.swift */; };
   19.87 @@ -406,10 +411,13 @@
   19.88  		B722EC7A1E5C879000A2B9D5 /* FolderUiProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = B722EC791E5C879000A2B9D5 /* FolderUiProtocols.swift */; };
   19.89  		B72C7BAA2395182F0013B12E /* AccountTypeSelectorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B72C7BA92395182F0013B12E /* AccountTypeSelectorViewController.swift */; };
   19.90  		B72C7BAC2395198D0013B12E /* AccountTypeSelectorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B72C7BAB2395198D0013B12E /* AccountTypeSelectorViewModel.swift */; };
   19.91 +		B72AC87423C494D2009B90B5 /* PerAccountSyncViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B72AC87323C494D2009B90B5 /* PerAccountSyncViewController.swift */; };
   19.92 +		B72AC87623C494FE009B90B5 /* PerAccountSyncViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B72AC87523C494FE009B90B5 /* PerAccountSyncViewModel.swift */; };
   19.93 +		B72AC87823C4A12A009B90B5 /* PerAccountSyncAccountTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B72AC87723C4A12A009B90B5 /* PerAccountSyncAccountTableViewCell.swift */; };
   19.94 +		B72E192423C7617B00CBC841 /* KeySyncSwitchSettingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B72E192323C7617B00CBC841 /* KeySyncSwitchSettingViewModel.swift */; };
   19.95  		B74F81021EB0E20000519FCC /* LoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B74F81011EB0E20000519FCC /* LoginViewModel.swift */; };
   19.96  		B75FF00B1EFD420F00C57289 /* EmailListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B75FF00A1EFD420F00C57289 /* EmailListViewModel.swift */; };
   19.97  		B76CF8B320D2739B002429A8 /* MoveToFolderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B76CF8B220D2739B002429A8 /* MoveToFolderViewModel.swift */; };
   19.98 -		B776A47B223962B50047A41D /* EmailListViewModel+MessageQueryResultsDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B776A47A223962B50047A41D /* EmailListViewModel+MessageQueryResultsDelegate.swift */; };
   19.99  		B78309C81EAA09040051A2E0 /* AccountCreation.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B78309C61EAA09040051A2E0 /* AccountCreation.storyboard */; };
  19.100  		B78CF8251E76D706008C1739 /* FilterTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B78CF8241E76D706008C1739 /* FilterTableViewController.swift */; };
  19.101  		B792889A2302D3DE00D2C68B /* Array+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B79288992302D3DE00D2C68B /* Array+Extension.swift */; };
  19.102 @@ -419,11 +427,9 @@
  19.103  		B7C7E3142334E7A1009ABFFE /* ResetTrustViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7C7E3132334E7A1009ABFFE /* ResetTrustViewModel.swift */; };
  19.104  		B7D1EEC81E8BEC8D00F190E3 /* CollapsibleTableViewHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7D1EEC71E8BEC8D00F190E3 /* CollapsibleTableViewHeader.swift */; };
  19.105  		B7DB7FC42215C4FF003968DA /* UINavigationController+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7DB7FC32215C4FF003968DA /* UINavigationController+Extensions.swift */; };
  19.106 -		B7DB7FC72215C57F003968DA /* UIView+Autolayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7DB7FC52215C57F003968DA /* UIView+Autolayout.swift */; };
  19.107  		B7DB7FC82215C57F003968DA /* UIView+Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7DB7FC62215C57F003968DA /* UIView+Util.swift */; };
  19.108  		B7DB7FCA2215D69C003968DA /* CredentialTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7DB7FC92215D69C003968DA /* CredentialTextField.swift */; };
  19.109  		B7DB7FD2221AD332003968DA /* SegueHandlerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7DB7FD1221AD332003968DA /* SegueHandlerType.swift */; };
  19.110 -		B7DB7FD6221AD3BB003968DA /* UITextField+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7DB7FD3221AD3BB003968DA /* UITextField+Extension.swift */; };
  19.111  		B7DB7FD7221AD3BB003968DA /* UIButton+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7DB7FD4221AD3BB003968DA /* UIButton+Extension.swift */; };
  19.112  		B7DB7FD8221AD3BB003968DA /* UITableView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7DB7FD5221AD3BB003968DA /* UITableView+Extension.swift */; };
  19.113  		B7DB7FDA221ADDAF003968DA /* UIBarButtonItem+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7DB7FD9221ADDAF003968DA /* UIBarButtonItem+Extension.swift */; };
  19.114 @@ -492,7 +498,6 @@
  19.115  		004422C92179ECD600BDF6DF /* PassiveModeViewModelTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PassiveModeViewModelTest.swift; sourceTree = "<group>"; };
  19.116  		004422D8217A25AD00BDF6DF /* UnencryptedSubjectViewModelTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnencryptedSubjectViewModelTest.swift; sourceTree = "<group>"; };
  19.117  		005A21FA20CAA5F50082D19F /* ThreadedEmailViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThreadedEmailViewModel.swift; sourceTree = "<group>"; };
  19.118 -		0069DCFA2110679200846EB1 /* EmailViewController+UIPopoverPresentationControllerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EmailViewController+UIPopoverPresentationControllerDelegate.swift"; sourceTree = "<group>"; };
  19.119  		006BE6BB20F4B63C00DDE8C9 /* EmailDetailType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailDetailType.swift; sourceTree = "<group>"; };
  19.120  		00A12CAD20D3D9AC00B82BE3 /* FullMessageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FullMessageCell.swift; sourceTree = "<group>"; };
  19.121  		00AEB2F520DBA7DA00DA185A /* NeedsRefreshDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NeedsRefreshDelegate.swift; sourceTree = "<group>"; };
  19.122 @@ -503,7 +508,6 @@
  19.123  		00EB89AC20E3D3C200CDFA0D /* ThreadedEmailViewModel+MoveToFolderDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ThreadedEmailViewModel+MoveToFolderDelegate.swift"; sourceTree = "<group>"; };
  19.124  		00EB89AE20E3E4A000CDFA0D /* ReplyAlertCreator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplyAlertCreator.swift; sourceTree = "<group>"; };
  19.125  		00FD0CE52101F7D700BA0C56 /* ScreenComposerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenComposerProtocol.swift; sourceTree = "<group>"; };
  19.126 -		00FD0CE72102014C00BA0C56 /* PrimarySplitViewcontroller+ScreenComposerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PrimarySplitViewcontroller+ScreenComposerProtocol.swift"; sourceTree = "<group>"; };
  19.127  		150707DB21006CD000AA213F /* ComposeUtilTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeUtilTest.swift; sourceTree = "<group>"; };
  19.128  		150B8E971FCDACBB00374438 /* AccountSettingsUserInputError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountSettingsUserInputError.swift; sourceTree = "<group>"; };
  19.129  		150B8EB21FCEB93D00374438 /* UIUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIUtils.swift; sourceTree = "<group>"; };
  19.130 @@ -625,6 +629,9 @@
  19.131  		15874BC02127493E00A3A4A6 /* TrustedServerSettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TrustedServerSettingsViewController.swift; sourceTree = "<group>"; };
  19.132  		15874BD321274BD400A3A4A6 /* TrustedServerSettingCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrustedServerSettingCell.swift; sourceTree = "<group>"; };
  19.133  		158A6E2E230D53E3006A9ECE /* ExtraKeysSettingViewModelTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtraKeysSettingViewModelTest.swift; sourceTree = "<group>"; };
  19.134 +		15944A2F239802D5006B133B /* EmailDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailDetailViewController.swift; sourceTree = "<group>"; };
  19.135 +		15944A3123980C99006B133B /* EmailDetailViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailDetailViewModel.swift; sourceTree = "<group>"; };
  19.136 +		15944A3423980FEC006B133B /* EmailDisplayViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailDisplayViewModel.swift; sourceTree = "<group>"; };
  19.137  		159AB56C23539D67008AB1F3 /* AppSettings+CNContactsAccessPermissionProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppSettings+CNContactsAccessPermissionProvider.swift"; sourceTree = "<group>"; };
  19.138  		159E1F1222BD074F007D711F /* PantomimeFramework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = PantomimeFramework.framework; sourceTree = BUILT_PRODUCTS_DIR; };
  19.139  		159E1F1422BD0756007D711F /* PEPObjCAdapterFramework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = PEPObjCAdapterFramework.framework; sourceTree = BUILT_PRODUCTS_DIR; };
  19.140 @@ -636,6 +643,8 @@
  19.141  		15BA536D20A095410090F126 /* UnifiedInboxTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnifiedInboxTest.swift; sourceTree = "<group>"; };
  19.142  		15BA537B20A1F5F50090F126 /* MoveToAccountViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoveToAccountViewController.swift; sourceTree = "<group>"; };
  19.143  		15BBBC6A1FD0527200B9DCC8 /* DisplayUserErrorTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayUserErrorTest.swift; sourceTree = "<group>"; };
  19.144 +		15D3D489239FC14700F2EBFB /* EmailDetailCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailDetailCollectionViewCell.swift; sourceTree = "<group>"; };
  19.145 +		15D3D48A239FC14700F2EBFB /* EmailDetailCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = EmailDetailCollectionViewCell.xib; sourceTree = "<group>"; };
  19.146  		15D43999216E697700EB3933 /* AccountPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountPickerView.swift; sourceTree = "<group>"; };
  19.147  		15D4399B216E698E00EB3933 /* AccountPickerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountPickerViewModel.swift; sourceTree = "<group>"; };
  19.148  		15D439A4216F7E0E00EB3933 /* AccountPickerViewModelTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountPickerViewModelTest.swift; sourceTree = "<group>"; };
  19.149 @@ -677,6 +686,7 @@
  19.150  		371D641C231D17390036AE62 /* StartUpTutorial.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartUpTutorial.swift; sourceTree = "<group>"; };
  19.151  		371D641F231D17F80036AE62 /* TutorialWizardViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TutorialWizardViewController.swift; sourceTree = "<group>"; };
  19.152  		3756434F2371B92200FB354D /* EditableAccountSettingsTableViewModelTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditableAccountSettingsTableViewModelTest.swift; sourceTree = "<group>"; };
  19.153 +		375BA089238BFC4100BBFE7C /* ManualAccountSetupContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManualAccountSetupContainerView.swift; sourceTree = "<group>"; };
  19.154  		37816541230EC72C00B967E3 /* PEPAlertViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PEPAlertViewController.swift; sourceTree = "<group>"; };
  19.155  		37816543230EC73900B967E3 /* PEPAlertViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PEPAlertViewModel.swift; sourceTree = "<group>"; };
  19.156  		37816545230EE5F700B967E3 /* PEPUIAlertAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PEPUIAlertAction.swift; sourceTree = "<group>"; };
  19.157 @@ -685,6 +695,10 @@
  19.158  		37A710DF233B5AA5001FEAF0 /* UIHelper+PEP.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIHelper+PEP.swift"; sourceTree = "<group>"; };
  19.159  		37C3C0E52260C64D003E290C /* Log.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Log.swift; sourceTree = "<group>"; };
  19.160  		37F272EF237075D9005C51AA /* EditableAccountSettingsViewModelTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditableAccountSettingsViewModelTest.swift; sourceTree = "<group>"; };
  19.161 +		37F615C82386B14A001AAE48 /* LoginScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginScrollView.swift; sourceTree = "<group>"; };
  19.162 +		37F615CB238BE51F001AAE48 /* ManualAccountSetupView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ManualAccountSetupView.xib; sourceTree = "<group>"; };
  19.163 +		37F615CE238BE584001AAE48 /* ManualAccountSetupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManualAccountSetupView.swift; sourceTree = "<group>"; };
  19.164 +		37FFA7F9234B3C27004229BE /* AnimatedPlaceholderTextfield.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimatedPlaceholderTextfield.swift; sourceTree = "<group>"; };
  19.165  		43040A521E9776220083DED8 /* AttachmentSummaryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttachmentSummaryView.swift; sourceTree = "<group>"; };
  19.166  		4304FCFE1EBB8C5A0086DADA /* LanguageListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LanguageListViewController.swift; sourceTree = "<group>"; };
  19.167  		4307D5D923575853004569C4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
  19.168 @@ -875,10 +889,9 @@
  19.169  		43EC75B22164E97800048CFE /* DecryptionUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecryptionUtil.swift; sourceTree = "<group>"; };
  19.170  		43ED53631CC77F95006AB156 /* EmailListViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmailListViewCell.swift; sourceTree = "<group>"; };
  19.171  		43ED53641CC77F95006AB156 /* EmailListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmailListViewController.swift; sourceTree = "<group>"; };
  19.172 -		43ED53661CC77F95006AB156 /* IMAPSettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IMAPSettingsTableViewController.swift; sourceTree = "<group>"; };
  19.173 -		43ED536C1CC77F95006AB156 /* OneValueSettingCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OneValueSettingCell.swift; sourceTree = "<group>"; };
  19.174 -		43ED536D1CC77F95006AB156 /* SMTPSettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMTPSettingsTableViewController.swift; sourceTree = "<group>"; };
  19.175 -		43ED536E1CC77F95006AB156 /* UserInfoTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserInfoTableViewController.swift; sourceTree = "<group>"; };
  19.176 +		43ED53661CC77F95006AB156 /* IMAPSettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IMAPSettingsViewController.swift; sourceTree = "<group>"; };
  19.177 +		43ED536D1CC77F95006AB156 /* SMTPSettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMTPSettingsViewController.swift; sourceTree = "<group>"; };
  19.178 +		43ED536E1CC77F95006AB156 /* UserInfoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserInfoViewController.swift; sourceTree = "<group>"; };
  19.179  		43F7F0791F6AD44600BDF151 /* HandshakeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HandshakeTests.swift; sourceTree = "<group>"; };
  19.180  		43F7F07B1F6AD4FD00BDF151 /* HandshakeTests_mail_001.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = HandshakeTests_mail_001.txt; sourceTree = "<group>"; };
  19.181  		43F9D9991E92725700F78A1C /* AttachmentsViewHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttachmentsViewHelper.swift; sourceTree = "<group>"; };
  19.182 @@ -887,7 +900,6 @@
  19.183  		4902244E20E50488000E8D7C /* ThreadNavigationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadNavigationDelegate.swift; sourceTree = "<group>"; };
  19.184  		49079D9821E3867900D15A0D /* javascript.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = javascript.pdf; sourceTree = "<group>"; };
  19.185  		490CEBA62100EAD500E8579C /* SelfDismissable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelfDismissable.swift; sourceTree = "<group>"; };
  19.186 -		490CEBA821020BF900E8579C /* LoginViewController+Keyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LoginViewController+Keyboard.swift"; sourceTree = "<group>"; };
  19.187  		491116BC216E0DF4005A42D2 /* MessageViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageViewModelTests.swift; sourceTree = "<group>"; };
  19.188  		4918EBFA1E783C70006207FC /* CdMessage+PantomimeTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CdMessage+PantomimeTest.swift"; sourceTree = "<group>"; };
  19.189  		491B656120CFE0FD00C2ADDA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Thread.storyboard; sourceTree = "<group>"; };
  19.190 @@ -896,7 +908,6 @@
  19.191  		492EF92C20C6957D004EAE14 /* ThreadViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadViewController.swift; sourceTree = "<group>"; };
  19.192  		492EF92E20C699D0004EAE14 /* ThreadViewController+TableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ThreadViewController+TableView.swift"; sourceTree = "<group>"; };
  19.193  		495D69BE20DBAEE900986007 /* ThreadViewController+SwipeCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ThreadViewController+SwipeCell.swift"; sourceTree = "<group>"; };
  19.194 -		495F607B20B564CD00F47BD6 /* EmailViewController+SizeClasses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EmailViewController+SizeClasses.swift"; sourceTree = "<group>"; };
  19.195  		495F689921E6600500A10C63 /* ScreenshotTestUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenshotTestUtil.swift; sourceTree = "<group>"; };
  19.196  		496355B020ECEA2900AA4387 /* ThreadedEmailViewModel+EmailDisplayDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ThreadedEmailViewModel+EmailDisplayDelegate.swift"; sourceTree = "<group>"; };
  19.197  		49691B1420D7FD0200CA9367 /* MessageViewModelConfigurable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageViewModelConfigurable.swift; sourceTree = "<group>"; };
  19.198 @@ -916,10 +927,13 @@
  19.199  		B722EC791E5C879000A2B9D5 /* FolderUiProtocols.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FolderUiProtocols.swift; sourceTree = "<group>"; };
  19.200  		B72C7BA92395182F0013B12E /* AccountTypeSelectorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountTypeSelectorViewController.swift; sourceTree = "<group>"; };
  19.201  		B72C7BAB2395198D0013B12E /* AccountTypeSelectorViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountTypeSelectorViewModel.swift; sourceTree = "<group>"; };
  19.202 +		B72AC87323C494D2009B90B5 /* PerAccountSyncViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PerAccountSyncViewController.swift; sourceTree = "<group>"; };
  19.203 +		B72AC87523C494FE009B90B5 /* PerAccountSyncViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PerAccountSyncViewModel.swift; sourceTree = "<group>"; };
  19.204 +		B72AC87723C4A12A009B90B5 /* PerAccountSyncAccountTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PerAccountSyncAccountTableViewCell.swift; sourceTree = "<group>"; };
  19.205 +		B72E192323C7617B00CBC841 /* KeySyncSwitchSettingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeySyncSwitchSettingViewModel.swift; sourceTree = "<group>"; };
  19.206  		B74F81011EB0E20000519FCC /* LoginViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginViewModel.swift; sourceTree = "<group>"; };
  19.207  		B75FF00A1EFD420F00C57289 /* EmailListViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmailListViewModel.swift; sourceTree = "<group>"; };
  19.208  		B76CF8B220D2739B002429A8 /* MoveToFolderViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoveToFolderViewModel.swift; sourceTree = "<group>"; };
  19.209 -		B776A47A223962B50047A41D /* EmailListViewModel+MessageQueryResultsDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EmailListViewModel+MessageQueryResultsDelegate.swift"; sourceTree = "<group>"; };
  19.210  		B78309C71EAA09040051A2E0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/AccountCreation.storyboard; sourceTree = "<group>"; };
  19.211  		B78CF8241E76D706008C1739 /* FilterTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FilterTableViewController.swift; path = Filter/FilterTableViewController.swift; sourceTree = "<group>"; };
  19.212  		B79288992302D3DE00D2C68B /* Array+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Extension.swift"; sourceTree = "<group>"; };
  19.213 @@ -929,11 +943,9 @@
  19.214  		B7C7E3132334E7A1009ABFFE /* ResetTrustViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetTrustViewModel.swift; sourceTree = "<group>"; };
  19.215  		B7D1EEC71E8BEC8D00F190E3 /* CollapsibleTableViewHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CollapsibleTableViewHeader.swift; path = Folder/CollapsibleTableViewHeader.swift; sourceTree = "<group>"; };
  19.216  		B7DB7FC32215C4FF003968DA /* UINavigationController+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UINavigationController+Extensions.swift"; sourceTree = "<group>"; };
  19.217 -		B7DB7FC52215C57F003968DA /* UIView+Autolayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Autolayout.swift"; sourceTree = "<group>"; };
  19.218  		B7DB7FC62215C57F003968DA /* UIView+Util.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Util.swift"; sourceTree = "<group>"; };
  19.219  		B7DB7FC92215D69C003968DA /* CredentialTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CredentialTextField.swift; sourceTree = "<group>"; };
  19.220  		B7DB7FD1221AD332003968DA /* SegueHandlerType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SegueHandlerType.swift; sourceTree = "<group>"; };
  19.221 -		B7DB7FD3221AD3BB003968DA /* UITextField+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UITextField+Extension.swift"; sourceTree = "<group>"; };
  19.222  		B7DB7FD4221AD3BB003968DA /* UIButton+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIButton+Extension.swift"; sourceTree = "<group>"; };
  19.223  		B7DB7FD5221AD3BB003968DA /* UITableView+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UITableView+Extension.swift"; sourceTree = "<group>"; };
  19.224  		B7DB7FD9221ADDAF003968DA /* UIBarButtonItem+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIBarButtonItem+Extension.swift"; sourceTree = "<group>"; };
  19.225 @@ -1002,7 +1014,6 @@
  19.226  			isa = PBXGroup;
  19.227  			children = (
  19.228  				00D3CD3D20B58976009ABBC9 /* PrimarySplitViewController.swift */,
  19.229 -				00FD0CE72102014C00BA0C56 /* PrimarySplitViewcontroller+ScreenComposerProtocol.swift */,
  19.230  				00BEC89620B85FD300A36E60 /* NothingSelectedViewController.swift */,
  19.231  				00FD0CE52101F7D700BA0C56 /* ScreenComposerProtocol.swift */,
  19.232  			);
  19.233 @@ -1433,6 +1444,7 @@
  19.234  		15874BAF2127493E00A3A4A6 /* Setting */ = {
  19.235  			isa = PBXGroup;
  19.236  			children = (
  19.237 +				B72AC87223C4947B009B90B5 /* KeySyncSettings */,
  19.238  				B7C7E3102334E028009ABFFE /* TrustSetting */,
  19.239  				43EC75AA2164C24800048CFE /* SetOwnKey */,
  19.240  				15874BB02127493E00A3A4A6 /* SettingDefaultAccountTableViewController.swift */,
  19.241 @@ -1519,6 +1531,31 @@
  19.242  			path = ExtraKeysSetting;
  19.243  			sourceTree = "<group>";
  19.244  		};
  19.245 +		15944A2E2397FF75006B133B /* EmailDetailView */ = {
  19.246 +			isa = PBXGroup;
  19.247 +			children = (
  19.248 +				15944A2F239802D5006B133B /* EmailDetailViewController.swift */,
  19.249 +				15944A3123980C99006B133B /* EmailDetailViewModel.swift */,
  19.250 +				15D3D489239FC14700F2EBFB /* EmailDetailCollectionViewCell.swift */,
  19.251 +				15D3D48A239FC14700F2EBFB /* EmailDetailCollectionViewCell.xib */,
  19.252 +			);
  19.253 +			path = EmailDetailView;
  19.254 +			sourceTree = "<group>";
  19.255 +		};
  19.256 +		15944A3323980E62006B133B /* EmailView */ = {
  19.257 +			isa = PBXGroup;
  19.258 +			children = (
  19.259 +				431E8F7D1CFDCF3A00C33647 /* EmailViewController.swift */,
  19.260 +				006BE6BB20F4B63C00DDE8C9 /* EmailDetailType.swift */,
  19.261 +				1526594E216230B0006A78DF /* Stuff that is named Compose but is used only in EmailView */,
  19.262 +				B70D32B1205BD3E80094A92A /* CellAndSections */,
  19.263 +				430D73601E9CBD0600EA6FA9 /* Background */,
  19.264 +				4323FE871E83E502006785E1 /* Util */,
  19.265 +				220DCE2D1E0AB544002FE716 /* MessageData.plist */,
  19.266 +			);
  19.267 +			path = EmailView;
  19.268 +			sourceTree = "<group>";
  19.269 +		};
  19.270  		15BA537A20A1F5CA0090F126 /* MoveToFolder */ = {
  19.271  			isa = PBXGroup;
  19.272  			children = (
  19.273 @@ -2056,6 +2093,7 @@
  19.274  				15D43998216E695500EB3933 /* AccountPicker */,
  19.275  				15265973216234C0006A78DF /* SuggestTableViewController */,
  19.276  				150DF6D12052A99800A9DCF7 /* SecureWebViewController */,
  19.277 +				37FFA7F9234B3C27004229BE /* AnimatedPlaceholderTextfield.swift */,
  19.278  				B7DB7FD1221AD332003968DA /* SegueHandlerType.swift */,
  19.279  				43C322081EA90192005073FB /* PEP+UI.swift */,
  19.280  				4330278D1F7BABFF00D685F8 /* GradientView.swift */,
  19.281 @@ -2074,6 +2112,7 @@
  19.282  				B7DFEA51225368670080A2BA /* VirtualFolder.swift */,
  19.283  				B7DFEA5322536D5E0080A2BA /* UnifiedInbox.swift */,
  19.284  				3705096B22DC8C1800CB73D6 /* KeyInputView.swift */,
  19.285 +				37F615C82386B14A001AAE48 /* LoginScrollView.swift */,
  19.286  			);
  19.287  			path = Util;
  19.288  			sourceTree = "<group>";
  19.289 @@ -2185,7 +2224,6 @@
  19.290  				15265942216230B0006A78DF /* Compose */,
  19.291  				15FE1F741FE122B200CC2D97 /* Credits */,
  19.292  				B70D32B0205BCFBD0094A92A /* EmailDisplay */,
  19.293 -				43ED53621CC77F95006AB156 /* EmailDisplayList */,
  19.294  				B78CF8261E76D70D008C1739 /* Filter */,
  19.295  				B71EBBB41E55E43100150177 /* Folder */,
  19.296  				432E80FA2191AF5100359879 /* Fonts */,
  19.297 @@ -2215,8 +2253,7 @@
  19.298  		43ED53651CC77F95006AB156 /* ImapSetup */ = {
  19.299  			isa = PBXGroup;
  19.300  			children = (
  19.301 -				B70D32AE205BCF380094A92A /* CellsAndSections */,
  19.302 -				43ED53661CC77F95006AB156 /* IMAPSettingsTableViewController.swift */,
  19.303 +				43ED53661CC77F95006AB156 /* IMAPSettingsViewController.swift */,
  19.304  			);
  19.305  			path = ImapSetup;
  19.306  			sourceTree = "<group>";
  19.307 @@ -2362,7 +2399,6 @@
  19.308  			children = (
  19.309  				B70D32AB205BCCDD0094A92A /* ViewModel */,
  19.310  				49D3BECB20F8F7330043E05D /* LoginViewController.swift */,
  19.311 -				490CEBA821020BF900E8579C /* LoginViewController+Keyboard.swift */,
  19.312  				B72C7BA92395182F0013B12E /* AccountTypeSelectorViewController.swift */,
  19.313  			);
  19.314  			path = Login;
  19.315 @@ -2383,7 +2419,7 @@
  19.316  		B70D32AC205BCEFB0094A92A /* SMTPSetup */ = {
  19.317  			isa = PBXGroup;
  19.318  			children = (
  19.319 -				43ED536D1CC77F95006AB156 /* SMTPSettingsTableViewController.swift */,
  19.320 +				43ED536D1CC77F95006AB156 /* SMTPSettingsViewController.swift */,
  19.321  			);
  19.322  			path = SMTPSetup;
  19.323  			sourceTree = "<group>";
  19.324 @@ -2391,22 +2427,17 @@
  19.325  		B70D32AD205BCF130094A92A /* InfoUserSettup */ = {
  19.326  			isa = PBXGroup;
  19.327  			children = (
  19.328 -				43ED536E1CC77F95006AB156 /* UserInfoTableViewController.swift */,
  19.329 +				43ED536E1CC77F95006AB156 /* UserInfoViewController.swift */,
  19.330  			);
  19.331  			path = InfoUserSettup;
  19.332  			sourceTree = "<group>";
  19.333  		};
  19.334 -		B70D32AE205BCF380094A92A /* CellsAndSections */ = {
  19.335 -			isa = PBXGroup;
  19.336 -			children = (
  19.337 -				43ED536C1CC77F95006AB156 /* OneValueSettingCell.swift */,
  19.338 -			);
  19.339 -			path = CellsAndSections;
  19.340 -			sourceTree = "<group>";
  19.341 -		};
  19.342  		B70D32AF205BCF460094A92A /* ManualLogin */ = {
  19.343  			isa = PBXGroup;
  19.344  			children = (
  19.345 +				37F615CB238BE51F001AAE48 /* ManualAccountSetupView.xib */,
  19.346 +				37F615CE238BE584001AAE48 /* ManualAccountSetupView.swift */,
  19.347 +				375BA089238BFC4100BBFE7C /* ManualAccountSetupContainerView.swift */,
  19.348  				43ED53651CC77F95006AB156 /* ImapSetup */,
  19.349  				B70D32AC205BCEFB0094A92A /* SMTPSetup */,
  19.350  				B70D32AD205BCF130094A92A /* InfoUserSettup */,
  19.351 @@ -2417,15 +2448,10 @@
  19.352  		B70D32B0205BCFBD0094A92A /* EmailDisplay */ = {
  19.353  			isa = PBXGroup;
  19.354  			children = (
  19.355 -				1526594E216230B0006A78DF /* Stuff that is named Compose but is used only in EmailView */,
  19.356 -				B70D32B1205BD3E80094A92A /* CellAndSections */,
  19.357 -				430D73601E9CBD0600EA6FA9 /* Background */,
  19.358 -				4323FE871E83E502006785E1 /* Util */,
  19.359 -				220DCE2D1E0AB544002FE716 /* MessageData.plist */,
  19.360 -				431E8F7D1CFDCF3A00C33647 /* EmailViewController.swift */,
  19.361 -				495F607B20B564CD00F47BD6 /* EmailViewController+SizeClasses.swift */,
  19.362 -				006BE6BB20F4B63C00DDE8C9 /* EmailDetailType.swift */,
  19.363 -				0069DCFA2110679200846EB1 /* EmailViewController+UIPopoverPresentationControllerDelegate.swift */,
  19.364 +				15944A2E2397FF75006B133B /* EmailDetailView */,
  19.365 +				43ED53621CC77F95006AB156 /* EmailDisplayList */,
  19.366 +				15944A3323980E62006B133B /* EmailView */,
  19.367 +				15944A3423980FEC006B133B /* EmailDisplayViewModel.swift */,
  19.368  			);
  19.369  			path = EmailDisplay;
  19.370  			sourceTree = "<group>";
  19.371 @@ -2472,6 +2498,33 @@
  19.372  			name = CellsAndSections;
  19.373  			sourceTree = "<group>";
  19.374  		};
  19.375 +		B72AC87223C4947B009B90B5 /* KeySyncSettings */ = {
  19.376 +			isa = PBXGroup;
  19.377 +			children = (
  19.378 +				B72E192223C7614200CBC841 /* PerAccountSetting */,
  19.379 +				B72E192323C7617B00CBC841 /* KeySyncSwitchSettingViewModel.swift */,
  19.380 +			);
  19.381 +			path = KeySyncSettings;
  19.382 +			sourceTree = "<group>";
  19.383 +		};
  19.384 +		B72AC87923C4A13B009B90B5 /* ViewModel */ = {
  19.385 +			isa = PBXGroup;
  19.386 +			children = (
  19.387 +				B72AC87523C494FE009B90B5 /* PerAccountSyncViewModel.swift */,
  19.388 +			);
  19.389 +			path = ViewModel;
  19.390 +			sourceTree = "<group>";
  19.391 +		};
  19.392 +		B72E192223C7614200CBC841 /* PerAccountSetting */ = {
  19.393 +			isa = PBXGroup;
  19.394 +			children = (
  19.395 +				B72AC87723C4A12A009B90B5 /* PerAccountSyncAccountTableViewCell.swift */,
  19.396 +				B72AC87323C494D2009B90B5 /* PerAccountSyncViewController.swift */,
  19.397 +				B72AC87923C4A13B009B90B5 /* ViewModel */,
  19.398 +			);
  19.399 +			path = PerAccountSetting;
  19.400 +			sourceTree = "<group>";
  19.401 +		};
  19.402  		B74D08BF1F013F15003D092C /* ViewModel */ = {
  19.403  			isa = PBXGroup;
  19.404  			children = (
  19.405 @@ -2479,7 +2532,6 @@
  19.406  				B75FF00A1EFD420F00C57289 /* EmailListViewModel.swift */,
  19.407  				49691B1420D7FD0200CA9367 /* MessageViewModelConfigurable.swift */,
  19.408  				43E1619020D7B2D6003F1514 /* UpdateThreadListDelegate.swift */,
  19.409 -				B776A47A223962B50047A41D /* EmailListViewModel+MessageQueryResultsDelegate.swift */,
  19.410  			);
  19.411  			name = ViewModel;
  19.412  			sourceTree = "<group>";
  19.413 @@ -2526,9 +2578,7 @@
  19.414  				B7DB7FD9221ADDAF003968DA /* UIBarButtonItem+Extension.swift */,
  19.415  				B7DB7FD4221AD3BB003968DA /* UIButton+Extension.swift */,
  19.416  				B7DB7FD5221AD3BB003968DA /* UITableView+Extension.swift */,
  19.417 -				B7DB7FD3221AD3BB003968DA /* UITextField+Extension.swift */,
  19.418  				B7DB7FC62215C57F003968DA /* UIView+Util.swift */,
  19.419 -				B7DB7FC52215C57F003968DA /* UIView+Autolayout.swift */,
  19.420  				B7DB7FC32215C4FF003968DA /* UINavigationController+Extensions.swift */,
  19.421  				37156E52234DD4CC00845A28 /* UIViewController */,
  19.422  				434AC3E220A450D700C11B7F /* UIAlertController+Extension.swift */,
  19.423 @@ -2687,6 +2737,7 @@
  19.424  				432E80FE2191AF5100359879 /* UniversLTStd-Bold.otf in Resources */,
  19.425  				43980E311CBD0BCA00A7FC3C /* Assets.xcassets in Resources */,
  19.426  				4307D5DA23575853004569C4 /* InfoPlist.strings in Resources */,
  19.427 +				37F615CC238BE51F001AAE48 /* ManualAccountSetupView.xib in Resources */,
  19.428  				151DE7E41FC5D41600CDC273 /* FolderViews.storyboard in Resources */,
  19.429  				152A39D221905C3E00D9F8E4 /* AttachmentCell.xib in Resources */,
  19.430  				B78309C81EAA09040051A2E0 /* AccountCreation.storyboard in Resources */,
  19.431 @@ -2696,6 +2747,7 @@
  19.432  				151DE7E11FC5D3FA00CDC273 /* Handshake.storyboard in Resources */,
  19.433  				43980E2C1CBD0BC900A7FC3C /* Main.storyboard in Resources */,
  19.434  				432E80FD2191AF5100359879 /* UniversLTStd.otf in Resources */,
  19.435 +				15D3D48C239FC14700F2EBFB /* EmailDetailCollectionViewCell.xib in Resources */,
  19.436  				151DE7DE1FC5D3E200CDC273 /* Settings.storyboard in Resources */,
  19.437  			);
  19.438  			runOnlyForDeploymentPostprocessing = 0;
  19.439 @@ -2836,11 +2888,11 @@
  19.440  				492EF92D20C6957D004EAE14 /* ThreadViewController.swift in Sources */,
  19.441  				43257C821F50179800DDC7F0 /* BasicSaxParser.swift in Sources */,
  19.442  				150DF6D02052A13700A9DCF7 /* SecureWebViewController.swift in Sources */,
  19.443 +				375BA08A238BFC4100BBFE7C /* ManualAccountSetupContainerView.swift in Sources */,
  19.444  				4351C2D71F4441190053381F /* node.c in Sources */,
  19.445  				154660D42334E2FC008D2137 /* Message+SecurityBadge.swift in Sources */,
  19.446  				00D3CD3E20B58976009ABBC9 /* PrimarySplitViewController.swift in Sources */,
  19.447  				B7DFEA56225397AB0080A2BA /* Folder+LocalizedName.swift in Sources */,
  19.448 -				43ED53771CC77F95006AB156 /* OneValueSettingCell.swift in Sources */,
  19.449  				4351C2D51F4441190053381F /* latex.c in Sources */,
  19.450  				37156E4C234CDDF100845A28 /* EditableAccountSettingsTableViewModel.swift in Sources */,
  19.451  				37816546230EE5F700B967E3 /* PEPUIAlertAction.swift in Sources */,
  19.452 @@ -2855,6 +2907,7 @@
  19.453  				15874BC92127493E00A3A4A6 /* PassiveModeViewModel.swift in Sources */,
  19.454  				B7DFEA5422536D5E0080A2BA /* UnifiedInbox.swift in Sources */,
  19.455  				4334CF302020CFFE00B3193E /* OAuth2Type+LibAccountSettings.swift in Sources */,
  19.456 +				B72AC87423C494D2009B90B5 /* PerAccountSyncViewController.swift in Sources */,
  19.457  				371D641D231D17390036AE62 /* StartUpTutorial.swift in Sources */,
  19.458  				37033E9B231AD8FE008DD6F0 /* KeySyncErrorView.swift in Sources */,
  19.459  				00A12CAE20D3D9AC00B82BE3 /* FullMessageCell.swift in Sources */,
  19.460 @@ -2884,14 +2937,13 @@
  19.461  				431D60DB1E93BB2D001266D7 /* AttachmentsView.swift in Sources */,
  19.462  				1574D078211356E000FEDC93 /* UrlClickHandlerProtocol.swift in Sources */,
  19.463  				152A39D621905C3E00D9F8E4 /* BodyCell.swift in Sources */,
  19.464 -				43ED53791CC77F95006AB156 /* UserInfoTableViewController.swift in Sources */,
  19.465 +				43ED53791CC77F95006AB156 /* UserInfoViewController.swift in Sources */,
  19.466  				43EC75AC2164C26100048CFE /* SetOwnKeyViewController.swift in Sources */,
  19.467  				B7F676BD227C4B26007E5E3A /* MessageQueryResultsFilter+FilterButtonTitle.swift in Sources */,
  19.468  				B7A50746224CD27A007B988F /* FilterViewModel.swift in Sources */,
  19.469  				220DCE2E1E0AB544002FE716 /* MessageCell.swift in Sources */,
  19.470  				B7DB7FD8221AD3BB003968DA /* UITableView+Extension.swift in Sources */,
  19.471  				8B69E3991E30F80E0022959E /* Appearance.swift in Sources */,
  19.472 -				B7DB7FD6221AD3BB003968DA /* UITextField+Extension.swift in Sources */,
  19.473  				B716056020D3ECC900A733D6 /* MoveToFolderTableViewController.swift in Sources */,
  19.474  				1543B6B022ABF53C002B59AB /* KeySyncDeviceGroupUtil.swift in Sources */,
  19.475  				15874BCB2127493E00A3A4A6 /* AccountVerificationResultDelegate.swift in Sources */,
  19.476 @@ -2907,12 +2959,10 @@
  19.477  				B70A3A63220065F600EDCE61 /* String+pEp.swift in Sources */,
  19.478  				15874BC12127493E00A3A4A6 /* SettingSwitchTableViewCell.swift in Sources */,
  19.479  				152A39E721905C3E00D9F8E4 /* RecipientTextViewModel.swift in Sources */,
  19.480 -				B776A47B223962B50047A41D /* EmailListViewModel+MessageQueryResultsDelegate.swift in Sources */,
  19.481  				4351C2D41F4441190053381F /* iterator.c in Sources */,
  19.482  				43AA825B1E9BC5FF00ABD5A8 /* AttachmentViewContainer.swift in Sources */,
  19.483 -				490CEBA921020BF900E8579C /* LoginViewController+Keyboard.swift in Sources */,
  19.484  				152A39D721905C3E00D9F8E4 /* TextAttachment.swift in Sources */,
  19.485 -				43ED53711CC77F95006AB156 /* IMAPSettingsTableViewController.swift in Sources */,
  19.486 +				43ED53711CC77F95006AB156 /* IMAPSettingsViewController.swift in Sources */,
  19.487  				43EC75AE2164D03500048CFE /* SetOwnKeyViewModel.swift in Sources */,
  19.488  				43257C891F50683600DDC7F0 /* NSAttributedString+pEp.swift in Sources */,
  19.489  				431E8F7E1CFDCF3A00C33647 /* EmailViewController.swift in Sources */,
  19.490 @@ -2955,12 +3005,14 @@
  19.491  				152A39D421905C3E00D9F8E4 /* SubjectCell.swift in Sources */,
  19.492  				B7DB7FD2221AD332003968DA /* SegueHandlerType.swift in Sources */,
  19.493  				0033C08320D7F41600224E61 /* ThreadedEmailViewModelDelegate.swift in Sources */,
  19.494 +				B72AC87623C494FE009B90B5 /* PerAccountSyncViewModel.swift in Sources */,
  19.495  				43498CDD200D0790006DC947 /* LoginViewModelOAuth2ErrorDelegate.swift in Sources */,
  19.496  				152A39DF21905C3E00D9F8E4 /* WrappedBccViewModel.swift in Sources */,
  19.497  				B74F81021EB0E20000519FCC /* LoginViewModel.swift in Sources */,
  19.498  				B7DFEA52225368670080A2BA /* VirtualFolder.swift in Sources */,
  19.499  				B722EC7A1E5C879000A2B9D5 /* FolderUiProtocols.swift in Sources */,
  19.500  				A1B50A841CD26FF100B1A997 /* Constants.swift in Sources */,
  19.501 +				37F615CF238BE584001AAE48 /* ManualAccountSetupView.swift in Sources */,
  19.502  				15D4399C216E698E00EB3933 /* AccountPickerViewModel.swift in Sources */,
  19.503  				43985D0E204438480080FA9A /* AccountSettingsProtocol+Extension.swift in Sources */,
  19.504  				B7DB7FCA2215D69C003968DA /* CredentialTextField.swift in Sources */,
  19.505 @@ -2990,9 +3042,10 @@
  19.506  				15874BCC2127493E00A3A4A6 /* AccountSettingsViewModel.swift in Sources */,
  19.507  				434F40941EB0B173002FBF0D /* ObservableValue.swift in Sources */,
  19.508  				B7DB7FC42215C4FF003968DA /* UINavigationController+Extensions.swift in Sources */,
  19.509 +				15944A3523980FEC006B133B /* EmailDisplayViewModel.swift in Sources */,
  19.510  				430D73651E9CBD4E00EA6FA9 /* AttachmentsViewOperation.swift in Sources */,
  19.511 +				15944A3223980C99006B133B /* EmailDetailViewModel.swift in Sources */,
  19.512  				B7DB7FC82215C57F003968DA /* UIView+Util.swift in Sources */,
  19.513 -				495F607C20B564CD00F47BD6 /* EmailViewController+SizeClasses.swift in Sources */,
  19.514  				152A39CC21905C3E00D9F8E4 /* MediaAttachmentPickerProvider.swift in Sources */,
  19.515  				4351C2CD1F4441190053381F /* commonmark.c in Sources */,
  19.516  				B722EC651E5B49BA00A2B9D5 /* FolderSectionViewModel.swift in Sources */,
  19.517 @@ -3007,6 +3060,7 @@
  19.518  				43306EC21FE129840045DD00 /* OAuth2Type.swift in Sources */,
  19.519  				438052871FE3E1B100ACF729 /* OAuth2AuthorizationFactoryProtocol.swift in Sources */,
  19.520  				4356FFE52135448600804089 /* ReplyAllPossibleChecker.swift in Sources */,
  19.521 +				B72AC87823C4A12A009B90B5 /* PerAccountSyncAccountTableViewCell.swift in Sources */,
  19.522  				15146C8A237EE77A00D69495 /* SettingsInternalError.swift in Sources */,
  19.523  				15255B031F825CD100A2CFC9 /* IdentityImageTool.swift in Sources */,
  19.524  				152A39D121905C3E00D9F8E4 /* AttachmentViewModel.swift in Sources */,
  19.525 @@ -3015,6 +3069,7 @@
  19.526  				152A39E121905C3E00D9F8E4 /* RecipientCellViewModel+FieldType.swift in Sources */,
  19.527  				4351C2CC1F4441190053381F /* cmark_ctype.c in Sources */,
  19.528  				152A39DB21905C3E00D9F8E4 /* CellViewModel.swift in Sources */,
  19.529 +				15944A30239802D5006B133B /* EmailDetailViewController.swift in Sources */,
  19.530  				155050F01FE82356009CEAD2 /* UserNotificationTool.swift in Sources */,
  19.531  				430D73671E9CC54000EA6FA9 /* AttachmentToLocalURLOperation.swift in Sources */,
  19.532  				37156E44234CD47C00845A28 /* EditableAccountSettingsViewController.swift in Sources */,
  19.533 @@ -3025,7 +3080,6 @@
  19.534  				49D3BECC20F8F7330043E05D /* LoginViewController.swift in Sources */,
  19.535  				43425EDB1FE3DE6E004A2728 /* OAuth2ProviderProtocol.swift in Sources */,
  19.536  				1526596A216230B1006A78DF /* ComposeDataSource.swift in Sources */,
  19.537 -				0069DCFB2110679200846EB1 /* EmailViewController+UIPopoverPresentationControllerDelegate.swift in Sources */,
  19.538  				43106A192045716000693144 /* OAuth2ConfigurationProtocol+Extension.swift in Sources */,
  19.539  				43C322051EA89EED005073FB /* HandshakePartnerTableViewCell.swift in Sources */,
  19.540  				152A39C521905C3E00D9F8E4 /* ComposeTableViewController.swift in Sources */,
  19.541 @@ -3035,6 +3089,8 @@
  19.542  				43980EFA1CBD415700A7FC3C /* AppConfig.swift in Sources */,
  19.543  				1574D07A211464CC00FEDC93 /* URL+MailTo.swift in Sources */,
  19.544  				1574D09B21186A1D00FEDC93 /* AddToContactsViewController.swift in Sources */,
  19.545 +				37FFA7FA234B3C27004229BE /* AnimatedPlaceholderTextfield.swift in Sources */,
  19.546 +				B72E192423C7617B00CBC841 /* KeySyncSwitchSettingViewModel.swift in Sources */,
  19.547  				371D6420231D17F80036AE62 /* TutorialWizardViewController.swift in Sources */,
  19.548  				15FE1F761FE122D900CC2D97 /* CreditsViewController.swift in Sources */,
  19.549  				152A39942190587200D9F8E4 /* TextViewInTableViewScrollUtil.swift in Sources */,
  19.550 @@ -3046,9 +3102,10 @@
  19.551  				15874BD421274BD400A3A4A6 /* TrustedServerSettingCell.swift in Sources */,
  19.552  				A1014DA71D1173CD00C472A8 /* UIHelper.swift in Sources */,
  19.553  				3705096622CF688F00CB73D6 /* KeySyncHandshakeViewModel.swift in Sources */,
  19.554 +				37F615C92386B14A001AAE48 /* LoginScrollView.swift in Sources */,
  19.555  				49C34AF620E4F649009D11CC /* CellDetailTransition.swift in Sources */,
  19.556  				49228A5520D4035100A51E9D /* DetailCellSegue.swift in Sources */,
  19.557 -				00FD0CE82102014C00BA0C56 /* PrimarySplitViewcontroller+ScreenComposerProtocol.swift in Sources */,
  19.558 +				15D3D48B239FC14700F2EBFB /* EmailDetailCollectionViewCell.swift in Sources */,
  19.559  				152A39E821905C3E00D9F8E4 /* RecipientCellViewModel.swift in Sources */,
  19.560  				152A39CE21905C3E00D9F8E4 /* ComposeHelpers.swift in Sources */,
  19.561  				43985D0A2044296D0080FA9A /* OAuth2AuthViewModel.swift in Sources */,
  19.562 @@ -3083,11 +3140,10 @@
  19.563  				4351C2D91F4441190053381F /* render.c in Sources */,
  19.564  				B722EC4D1E5B01B300A2B9D5 /* FolderCellViewModel.swift in Sources */,
  19.565  				15874BCF2127493E00A3A4A6 /* AccountSettingsTableViewController.swift in Sources */,
  19.566 -				B7DB7FC72215C57F003968DA /* UIView+Autolayout.swift in Sources */,
  19.567  				B71EBBBC1E55E4AE00150177 /* FolderTableViewController.swift in Sources */,
  19.568  				492EF92F20C699D0004EAE14 /* ThreadViewController+TableView.swift in Sources */,
  19.569  				43D070312133DB920013B120 /* AppSettingsProtocol.swift in Sources */,
  19.570 -				43ED53781CC77F95006AB156 /* SMTPSettingsTableViewController.swift in Sources */,
  19.571 +				43ED53781CC77F95006AB156 /* SMTPSettingsViewController.swift in Sources */,
  19.572  				15874BC22127493E00A3A4A6 /* SettingCellViewModelProtocols.swift in Sources */,
  19.573  				15146C91237F07EF00D69495 /* PEPPageViewControllerBase.swift in Sources */,
  19.574  			);
  19.575 @@ -3476,7 +3532,7 @@
  19.576  				INFOPLIST_FILE = pEpForiOS/Info.plist;
  19.577  				IPHONEOS_DEPLOYMENT_TARGET = 10.0;
  19.578  				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
  19.579 -				MARKETING_VERSION = 1.0.907;
  19.580 +				MARKETING_VERSION = 1.0.910;
  19.581  				ONLY_ACTIVE_ARCH = "$(inherited)";
  19.582  				OTHER_SWIFT_FLAGS = "-DDEBUG_LOGGING -D DEBUG $(inherited)";
  19.583  				PRODUCT_BUNDLE_IDENTIFIER = security.pEp;
  19.584 @@ -3515,7 +3571,7 @@
  19.585  				INFOPLIST_FILE = pEpForiOS/Info.plist;
  19.586  				IPHONEOS_DEPLOYMENT_TARGET = 10.0;
  19.587  				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
  19.588 -				MARKETING_VERSION = 1.0.907;
  19.589 +				MARKETING_VERSION = 1.0.910;
  19.590  				ONLY_ACTIVE_ARCH = "$(inherited)";
  19.591  				PRODUCT_BUNDLE_IDENTIFIER = security.pEp;
  19.592  				PRODUCT_MODULE_NAME = pEpForiOS;
    20.1 --- a/pEpForiOS.xcodeproj/xcshareddata/xcschemes/pEp.xcscheme	Fri Feb 07 12:29:26 2020 +0100
    20.2 +++ b/pEpForiOS.xcodeproj/xcshareddata/xcschemes/pEp.xcscheme	Fri Feb 07 12:31:01 2020 +0100
    20.3 @@ -1,7 +1,7 @@
    20.4  <?xml version="1.0" encoding="UTF-8"?>
    20.5  <Scheme
    20.6     LastUpgradeVersion = "1110"
    20.7 -   version = "1.8">
    20.8 +   version = "1.3">
    20.9     <BuildAction
   20.10        parallelizeBuildables = "NO"
   20.11        buildImplicitDependencies = "YES">
   20.12 @@ -166,10 +166,31 @@
   20.13        buildConfiguration = "Debug"
   20.14        selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
   20.15        selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
   20.16 +      shouldUseLaunchSchemeArgsEnv = "YES"
   20.17        enableAddressSanitizer = "YES"
   20.18        enableASanStackUseAfterReturn = "YES"
   20.19 -      enableUBSanitizer = "YES"
   20.20 -      shouldUseLaunchSchemeArgsEnv = "YES">
   20.21 +      enableUBSanitizer = "YES">
   20.22 +      <MacroExpansion>
   20.23 +         <BuildableReference
   20.24 +            BuildableIdentifier = "primary"
   20.25 +            BlueprintIdentifier = "43980E221CBD0BC900A7FC3C"
   20.26 +            BuildableName = "pEp.app"
   20.27 +            BlueprintName = "pEp"
   20.28 +            ReferencedContainer = "container:pEpForiOS.xcodeproj">
   20.29 +         </BuildableReference>
   20.30 +      </MacroExpansion>
   20.31 +      <AdditionalOptions>
   20.32 +         <AdditionalOption
   20.33 +            key = "NSZombieEnabled"
   20.34 +            value = "YES"
   20.35 +            isEnabled = "YES">
   20.36 +         </AdditionalOption>
   20.37 +         <AdditionalOption
   20.38 +            key = "MallocScribble"
   20.39 +            value = ""
   20.40 +            isEnabled = "YES">
   20.41 +         </AdditionalOption>
   20.42 +      </AdditionalOptions>
   20.43        <Testables>
   20.44           <TestableReference
   20.45              skipped = "NO">
   20.46 @@ -232,27 +253,6 @@
   20.47              </BuildableReference>
   20.48           </TestableReference>
   20.49        </Testables>
   20.50 -      <MacroExpansion>
   20.51 -         <BuildableReference
   20.52 -            BuildableIdentifier = "primary"
   20.53 -            BlueprintIdentifier = "43980E221CBD0BC900A7FC3C"
   20.54 -            BuildableName = "pEp.app"
   20.55 -            BlueprintName = "pEp"
   20.56 -            ReferencedContainer = "container:pEpForiOS.xcodeproj">
   20.57 -         </BuildableReference>
   20.58 -      </MacroExpansion>
   20.59 -      <AdditionalOptions>
   20.60 -         <AdditionalOption
   20.61 -            key = "NSZombieEnabled"
   20.62 -            value = "YES"
   20.63 -            isEnabled = "YES">
   20.64 -         </AdditionalOption>
   20.65 -         <AdditionalOption
   20.66 -            key = "MallocScribble"
   20.67 -            value = ""
   20.68 -            isEnabled = "YES">
   20.69 -         </AdditionalOption>
   20.70 -      </AdditionalOptions>
   20.71     </TestAction>
   20.72     <LaunchAction
   20.73        buildConfiguration = "Debug"
   20.74 @@ -293,8 +293,6 @@
   20.75              isEnabled = "YES">
   20.76           </EnvironmentVariable>
   20.77        </EnvironmentVariables>
   20.78 -      <AdditionalOptions>
   20.79 -      </AdditionalOptions>
   20.80     </LaunchAction>
   20.81     <ProfileAction
   20.82        buildConfiguration = "Release"
    21.1 --- a/pEpForiOS/AppDelegate.swift	Fri Feb 07 12:29:26 2020 +0100
    21.2 +++ b/pEpForiOS/AppDelegate.swift	Fri Feb 07 12:31:01 2020 +0100
    21.3 @@ -64,12 +64,10 @@
    21.4  
    21.5      private func setupServices() {
    21.6          let keySyncHandshakeService = KeySyncHandshakeService()
    21.7 -        let theMessageModelService =
    21.8 -            MessageModelService(errorPropagator: errorPropagator,
    21.9 -                                cnContactsAccessPermissionProvider: AppSettings.shared,
   21.10 -                                keySyncServiceHandshakeDelegate: keySyncHandshakeService,
   21.11 -                                keySyncStateProvider: AppSettings.shared)
   21.12 -        messageModelService = theMessageModelService
   21.13 +        messageModelService = MessageModelService(errorPropagator: errorPropagator,
   21.14 +                                                  cnContactsAccessPermissionProvider: AppSettings.shared,
   21.15 +                                                  keySyncServiceHandshakeDelegate: keySyncHandshakeService,
   21.16 +                                                  keySyncStateProvider: AppSettings.shared)
   21.17  
   21.18          appConfig = AppConfig(errorPropagator: errorPropagator,
   21.19                                oauth2AuthorizationFactory: oauth2Provider,
   21.20 @@ -120,9 +118,11 @@
   21.21      /// - note: this is also called when:
   21.22      ///         * an alert is shown (e.g. OS asks for CNContact access permissions)
   21.23      ///         * the user swipes up/down the "ControllCenter"
   21.24 +    ///         * the keyboard is shown the first time on iOS13 and the "you can now swipe instead
   21.25 +    ///             of typing" view is shown
   21.26      func applicationWillResignActive(_ application: UIApplication) {
   21.27 -        UIApplication.hideStatusBarNetworkActivitySpinner()
   21.28 -        messageModelService?.finish()
   21.29 +        // We intentionally do nothing here.
   21.30 +        // We assume to be kept alive until being informed (by another delegate method) otherwize.
   21.31      }
   21.32  
   21.33      /// Use this method to release shared resources, save user data, invalidate timers, and store
   21.34 @@ -158,7 +158,8 @@
   21.35          messageModelService?.start()
   21.36      }
   21.37  
   21.38 -    /// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
   21.39 +    /// Called when the application is about to terminate. Save data if appropriate. See also
   21.40 +    /// applicationDidEnterBackground:.
   21.41      /// Saves changes in the application's managed object context before the application terminates.
   21.42      func applicationWillTerminate(_ application: UIApplication) {
   21.43          messageModelService?.stop()
    22.1 --- a/pEpForiOS/Base.lproj/FolderViews.storyboard	Fri Feb 07 12:29:26 2020 +0100
    22.2 +++ b/pEpForiOS/Base.lproj/FolderViews.storyboard	Fri Feb 07 12:31:01 2020 +0100
    22.3 @@ -33,7 +33,6 @@
    22.4                                      </state>
    22.5                                      <connections>
    22.6                                          <action selector="addAccountTapped:" destination="6ra-tc-Aiv" eventType="touchUpInside" id="OYg-F7-CRW"/>
    22.7 -                                        <segue destination="uKb-Ku-Cng" kind="presentation" identifier="newAccountIpad" modalPresentationStyle="formSheet" id="aKb-z0-Qyn"/>
    22.8                                      </connections>
    22.9                                  </button>
   22.10                              </subviews>
   22.11 @@ -65,6 +64,7 @@
   22.12                      <simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
   22.13                      <connections>
   22.14                          <segue destination="uKb-Ku-Cng" kind="presentation" identifier="newAccountIphone" id="W2T-ax-nDz"/>
   22.15 +                        <segue destination="uKb-Ku-Cng" kind="presentation" identifier="newAccountIpad" id="VWu-Lk-rKj"/>
   22.16                      </connections>
   22.17                  </tableViewController>
   22.18                  <placeholder placeholderIdentifier="IBFirstResponder" id="o2c-UY-yR4" userLabel="First Responder" sceneMemberID="firstResponder"/>
   22.19 @@ -74,7 +74,9 @@
   22.20          <!--AccountCreation-->
   22.21          <scene sceneID="rdR-gU-SsC">
   22.22              <objects>
   22.23 -                <viewControllerPlaceholder storyboardName="AccountCreation" id="uKb-Ku-Cng" sceneMemberID="viewController"/>
   22.24 +                <viewControllerPlaceholder storyboardName="AccountCreation" id="uKb-Ku-Cng" sceneMemberID="viewController">
   22.25 +                    <navigationItem key="navigationItem" id="HcY-vc-Krh"/>
   22.26 +                </viewControllerPlaceholder>
   22.27                  <placeholder placeholderIdentifier="IBFirstResponder" id="7bq-Lz-J44" userLabel="First Responder" sceneMemberID="firstResponder"/>
   22.28              </objects>
   22.29              <point key="canvasLocation" x="10635" y="-1077"/>
   22.30 @@ -123,6 +125,6 @@
   22.31          <image name="button-add" width="22" height="22"/>
   22.32      </resources>
   22.33      <inferredMetricsTieBreakers>
   22.34 -        <segue reference="aKb-z0-Qyn"/>
   22.35 +        <segue reference="W2T-ax-nDz"/>
   22.36      </inferredMetricsTieBreakers>
   22.37  </document>
    23.1 --- a/pEpForiOS/Base.lproj/Main.storyboard	Fri Feb 07 12:29:26 2020 +0100
    23.2 +++ b/pEpForiOS/Base.lproj/Main.storyboard	Fri Feb 07 12:31:01 2020 +0100
    23.3 @@ -1,206 +1,231 @@
    23.4  <?xml version="1.0" encoding="UTF-8"?>
    23.5 -<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
    23.6 +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15705" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
    23.7      <device id="retina4_7" orientation="portrait" appearance="light"/>
    23.8      <dependencies>
    23.9          <deployment identifier="iOS"/>
   23.10 -        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15510"/>
   23.11 +        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15706"/>
   23.12          <capability name="Safe area layout guides" minToolsVersion="9.0"/>
   23.13 +        <capability name="collection view cell content view" minToolsVersion="11.0"/>
   23.14          <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
   23.15      </dependencies>
   23.16      <scenes>
   23.17 -        <!--Thread-->
   23.18 -        <scene sceneID="Xet-dG-Ldx">
   23.19 +        <!--Navigation Controller-->
   23.20 +        <scene sceneID="e1W-O0-7gY">
   23.21              <objects>
   23.22 -                <viewControllerPlaceholder storyboardName="Thread" id="eLD-PA-Nmx" sceneMemberID="viewController"/>
   23.23 -                <placeholder placeholderIdentifier="IBFirstResponder" id="Vtu-PN-QTE" userLabel="First Responder" sceneMemberID="firstResponder"/>
   23.24 +                <navigationController toolbarHidden="NO" id="tTN-8A-7tU" sceneMemberID="viewController">
   23.25 +                    <navigationItem key="navigationItem" id="QPh-8P-Ikk"/>
   23.26 +                    <simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
   23.27 +                    <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="o6J-NN-Zae">
   23.28 +                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
   23.29 +                        <autoresizingMask key="autoresizingMask"/>
   23.30 +                    </navigationBar>
   23.31 +                    <toolbar key="toolbar" opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="vuK-vG-hkr">
   23.32 +                        <rect key="frame" x="0.0" y="623" width="375" height="44"/>
   23.33 +                        <autoresizingMask key="autoresizingMask"/>
   23.34 +                    </toolbar>
   23.35 +                    <connections>
   23.36 +                        <segue destination="fRo-D2-Fjz" kind="relationship" relationship="rootViewController" id="UBr-Ll-cMP"/>
   23.37 +                    </connections>
   23.38 +                </navigationController>
   23.39 +                <placeholder placeholderIdentifier="IBFirstResponder" id="wYS-Rz-jbd" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
   23.40              </objects>
   23.41 -            <point key="canvasLocation" x="3382" y="-877"/>
   23.42 +            <point key="canvasLocation" x="2818" y="-757"/>
   23.43          </scene>
   23.44 -        <!--Email List-->
   23.45 -        <scene sceneID="OWw-y9-SIo">
   23.46 +        <!--EmailListViewController-->
   23.47 +        <scene sceneID="ed4-cB-BMk">
   23.48              <objects>
   23.49 -                <tableViewController storyboardIdentifier="EmailListViewController" title="Email List" id="kcA-RK-9Xg" customClass="EmailListViewController" customModule="pEpForiOS" customModuleProvider="target" sceneMemberID="viewController">
   23.50 -                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="80" sectionHeaderHeight="28" sectionFooterHeight="28" id="smX-Ka-bhC">
   23.51 +                <viewController storyboardIdentifier="EmailListViewController" id="ldy-GA-D6J" userLabel="EmailListViewController" customClass="EmailListViewController" customModule="pEpForiOS" customModuleProvider="target" sceneMemberID="viewController">
   23.52 +                    <view key="view" contentMode="scaleToFill" id="sMB-1B-QXM">
   23.53                          <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
   23.54                          <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
   23.55 -                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
   23.56 -                        <prototypes>
   23.57 -                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="EmailListViewCell" rowHeight="90" id="uhL-VL-48i" customClass="EmailListViewCell" customModule="pEpForiOS" customModuleProvider="target">
   23.58 -                                <rect key="frame" x="0.0" y="28" width="375" height="90"/>
   23.59 -                                <autoresizingMask key="autoresizingMask"/>
   23.60 -                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="uhL-VL-48i" id="jgQ-nZ-h1r">
   23.61 -                                    <rect key="frame" x="0.0" y="0.0" width="375" height="90"/>
   23.62 -                                    <autoresizingMask key="autoresizingMask"/>
   23.63 -                                    <subviews>
   23.64 -                                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="id9-ga-Yy6">
   23.65 -                                            <rect key="frame" x="5" y="0.0" width="365" height="90"/>
   23.66 +                        <subviews>
   23.67 +                            <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="1Oj-l2-jRA">
   23.68 +                                <rect key="frame" x="0.0" y="44" width="375" height="574"/>
   23.69 +                                <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
   23.70 +                                <prototypes>
   23.71 +                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="EmailListViewCell" rowHeight="90" id="uoK-uW-SqQ" customClass="EmailListViewCell" customModule="pEpForiOS" customModuleProvider="target">
   23.72 +                                        <rect key="frame" x="0.0" y="28" width="375" height="90"/>
   23.73 +                                        <autoresizingMask key="autoresizingMask"/>
   23.74 +                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="uoK-uW-SqQ" id="DUw-sX-YAB">
   23.75 +                                            <rect key="frame" x="0.0" y="0.0" width="375" height="90"/>
   23.76 +                                            <autoresizingMask key="autoresizingMask"/>
   23.77                                              <subviews>
   23.78 -                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="750" verticalHuggingPriority="251" horizontalCompressionResistancePriority="250" verticalCompressionResistancePriority="1000" text="Sender" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tWZ-jW-sUg">
   23.79 -                                                    <rect key="frame" x="68" y="5" width="52" height="19.5"/>
   23.80 -                                                    <fontDescription key="fontDescription" style="UICTFontTextStyleCallout"/>
   23.81 -                                                    <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
   23.82 -                                                    <nil key="highlightedColor"/>
   23.83 -                                                </label>
   23.84 -                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalCompressionResistancePriority="1000" text="Summary" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="BvI-Zi-zU6">
   23.85 -                                                    <rect key="frame" x="68" y="52" width="289" height="20.5"/>
   23.86 -                                                    <fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
   23.87 -                                                    <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
   23.88 -                                                    <nil key="highlightedColor"/>
   23.89 -                                                </label>
   23.90 -                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalCompressionResistancePriority="1000" text="Subject" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5Py-55-oem">
   23.91 -                                                    <rect key="frame" x="68" y="28.5" width="272" height="19.5"/>
   23.92 -                                                    <fontDescription key="fontDescription" style="UICTFontTextStyleCallout"/>
   23.93 -                                                    <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
   23.94 -                                                    <nil key="highlightedColor"/>
   23.95 -                                                </label>
   23.96 -                                                <stackView opaque="NO" contentMode="scaleAspectFit" distribution="fillProportionally" alignment="center" spacing="6" translatesAutoresizingMaskIntoConstraints="NO" id="MZJ-bg-Dw7">
   23.97 -                                                    <rect key="frame" x="343" y="32.5" width="14" height="14"/>
   23.98 +                                                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="QAL-Vw-DX8">
   23.99 +                                                    <rect key="frame" x="5" y="0.0" width="365" height="90"/>
  23.100                                                      <subviews>
  23.101 -                                                        <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="attachment-list-icon" translatesAutoresizingMaskIntoConstraints="NO" id="3BC-6k-zL0">
  23.102 -                                                            <rect key="frame" x="-14" y="0.0" width="14" height="14"/>
  23.103 -                                                            <constraints>
  23.104 -                                                                <constraint firstAttribute="height" constant="14" id="BQW-DX-8aC"/>
  23.105 -                                                                <constraint firstAttribute="width" secondItem="3BC-6k-zL0" secondAttribute="height" multiplier="1:1" id="xsh-N2-oVw"/>
  23.106 -                                                            </constraints>
  23.107 -                                                        </imageView>
  23.108 -                                                        <imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="BLq-0g-OgR" userLabel="Flagged icon">
  23.109 -                                                            <rect key="frame" x="0.0" y="0.0" width="14" height="14"/>
  23.110 -                                                            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
  23.111 -                                                            <constraints>
  23.112 -                                                                <constraint firstAttribute="height" constant="14" id="f4y-vH-ugI"/>
  23.113 -                                                                <constraint firstAttribute="width" secondItem="BLq-0g-OgR" secondAttribute="height" multiplier="1:1" id="uGj-dI-2ly"/>
  23.114 -                                                            </constraints>
  23.115 -                                                        </imageView>
  23.116 -                                                    </subviews>
  23.117 -                                                </stackView>
  23.118 -                                                <stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="8QD-qP-0hS">
  23.119 -                                                    <rect key="frame" x="322.5" y="5" width="34.5" height="19.5"/>
  23.120 -                                                    <subviews>
  23.121 -                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" text="Date" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Wkg-wf-Dbd">
  23.122 -                                                            <rect key="frame" x="0.0" y="0.0" width="34.5" height="19.5"/>
  23.123 +                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="750" verticalHuggingPriority="251" horizontalCompressionResistancePriority="250" verticalCompressionResistancePriority="1000" text="Sender" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="KTi-T9-Inm">
  23.124 +                                                            <rect key="frame" x="68" y="5" width="52" height="19.5"/>
  23.125                                                              <fontDescription key="fontDescription" style="UICTFontTextStyleCallout"/>
  23.126 -                                                            <color key="textColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
  23.127 +                                                            <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
  23.128                                                              <nil key="highlightedColor"/>
  23.129                                                          </label>
  23.130 -                                                    </subviews>
  23.131 -                                                </stackView>
  23.132 -                                                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="UPT-Ig-AlN">
  23.133 -                                                    <rect key="frame" x="8" y="20" width="50" height="50"/>
  23.134 -                                                    <subviews>
  23.135 -                                                        <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="empty-avatar" translatesAutoresizingMaskIntoConstraints="NO" id="YqR-ga-Tf9" userLabel="Contact Image">
  23.136 -                                                            <rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
  23.137 +                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalCompressionResistancePriority="1000" text="Summary" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Tbi-dG-KCA">
  23.138 +                                                            <rect key="frame" x="68" y="52" width="289" height="20.5"/>
  23.139 +                                                            <fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
  23.140 +                                                            <color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="calibratedWhite"/>
  23.141 +                                                            <nil key="highlightedColor"/>
  23.142 +                                                        </label>
  23.143 +                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalCompressionResistancePriority="1000" text="Subject" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ha5-Vd-x3U">
  23.144 +                                                            <rect key="frame" x="68" y="28.5" width="272" height="19.5"/>
  23.145 +                                                            <fontDescription key="fontDescription" style="UICTFontTextStyleCallout"/>
  23.146 +                                                            <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
  23.147 +                                                            <nil key="highlightedColor"/>
  23.148 +                                                        </label>
  23.149 +                                                        <stackView opaque="NO" contentMode="scaleAspectFit" distribution="fillProportionally" alignment="center" spacing="6" translatesAutoresizingMaskIntoConstraints="NO" id="bNf-Dy-rbx">
  23.150 +                                                            <rect key="frame" x="343" y="32.5" width="14" height="14"/>
  23.151 +                                                            <subviews>
  23.152 +                                                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="attachment-list-icon" translatesAutoresizingMaskIntoConstraints="NO" id="qYK-Q0-GO5">
  23.153 +                                                                    <rect key="frame" x="-14" y="0.0" width="14" height="14"/>
  23.154 +                                                                    <constraints>
  23.155 +                                                                        <constraint firstAttribute="width" secondItem="qYK-Q0-GO5" secondAttribute="height" multiplier="1:1" id="grm-uS-Iyi"/>
  23.156 +                                                                        <constraint firstAttribute="height" constant="14" id="mYl-DL-WXV"/>
  23.157 +                                                                    </constraints>
  23.158 +                                                                </imageView>
  23.159 +                                                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="hoT-RP-AkI" userLabel="Flagged icon">
  23.160 +                                                                    <rect key="frame" x="0.0" y="0.0" width="14" height="14"/>
  23.161 +                                                                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
  23.162 +                                                                    <constraints>
  23.163 +                                                                        <constraint firstAttribute="height" constant="14" id="Tci-gI-qeg"/>
  23.164 +                                                                        <constraint firstAttribute="width" secondItem="hoT-RP-AkI" secondAttribute="height" multiplier="1:1" id="VBW-bh-VLb"/>
  23.165 +                                                                    </constraints>
  23.166 +                                                                </imageView>
  23.167 +                                                            </subviews>
  23.168 +                                                        </stackView>
  23.169 +                                                        <stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="cG7-zS-ib7">
  23.170 +                                                            <rect key="frame" x="322.5" y="5" width="34.5" height="19.5"/>
  23.171 +                                                            <subviews>
  23.172 +                                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" text="Date" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="a1D-BW-3Rd">
  23.173 +                                                                    <rect key="frame" x="0.0" y="0.0" width="34.5" height="19.5"/>
  23.174 +                                                                    <fontDescription key="fontDescription" style="UICTFontTextStyleCallout"/>
  23.175 +                                                                    <color key="textColor" red="0.66666666669999997" green="0.66666666669999997" blue="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
  23.176 +                                                                    <nil key="highlightedColor"/>
  23.177 +                                                                </label>
  23.178 +                                                            </subviews>
  23.179 +                                                        </stackView>
  23.180 +                                                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="wra-Ql-iZp">
  23.181 +                                                            <rect key="frame" x="8" y="20" width="50" height="50"/>
  23.182 +                                                            <subviews>
  23.183 +                                                                <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="empty-avatar" translatesAutoresizingMaskIntoConstraints="NO" id="ocF-vy-7Ef" userLabel="Contact Image">
  23.184 +                                                                    <rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
  23.185 +                                                                    <constraints>
  23.186 +                                                                        <constraint firstAttribute="width" constant="50" id="SxH-gw-Ygu"/>
  23.187 +                                                                        <constraint firstAttribute="width" secondItem="ocF-vy-7Ef" secondAttribute="height" multiplier="1:1" id="nBE-3s-ERQ"/>
  23.188 +                                                                    </constraints>
  23.189 +                                                                    <userDefinedRuntimeAttributes>
  23.190 +                                                                        <userDefinedRuntimeAttribute type="boolean" keyPath="translatesAutoresizingMaskIntoConstraints" value="NO"/>
  23.191 +                                                                    </userDefinedRuntimeAttributes>
  23.192 +                                                                </imageView>
  23.193 +                                                                <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" fixedFrame="YES" insetsLayoutMarginsFromSafeArea="NO" image="pEp-status-yellow" translatesAutoresizingMaskIntoConstraints="NO" id="gja-fY-c60">
  23.194 +                                                                    <rect key="frame" x="15" y="15" width="20" height="20"/>
  23.195 +                                                                    <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
  23.196 +                                                                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
  23.197 +                                                                    <userDefinedRuntimeAttributes>
  23.198 +                                                                        <userDefinedRuntimeAttribute type="boolean" keyPath="translatesAutoresizingMaskIntoConstraints" value="NO"/>
  23.199 +                                                                    </userDefinedRuntimeAttributes>
  23.200 +                                                                </imageView>
  23.201 +                                                            </subviews>
  23.202 +                                                            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
  23.203                                                              <constraints>
  23.204 -                                                                <constraint firstAttribute="width" secondItem="YqR-ga-Tf9" secondAttribute="height" multiplier="1:1" id="NF6-d0-Gji"/>
  23.205 -                                                                <constraint firstAttribute="width" constant="50" id="lsJ-yy-dQ3"/>
  23.206 +                                                                <constraint firstItem="ocF-vy-7Ef" firstAttribute="leading" secondItem="wra-Ql-iZp" secondAttribute="leading" id="Jve-F1-pdr"/>
  23.207 +                                                                <constraint firstAttribute="bottom" secondItem="ocF-vy-7Ef" secondAttribute="bottom" id="bbx-Am-jgz"/>
  23.208 +                                                                <constraint firstItem="ocF-vy-7Ef" firstAttribute="top" secondItem="wra-Ql-iZp" secondAttribute="top" id="eQL-Vi-ezR"/>
  23.209 +                                                                <constraint firstAttribute="trailing" secondItem="ocF-vy-7Ef" secondAttribute="trailing" id="epg-GW-QI8"/>
  23.210                                                              </constraints>
  23.211                                                              <userDefinedRuntimeAttributes>
  23.212                                                                  <userDefinedRuntimeAttribute type="boolean" keyPath="translatesAutoresizingMaskIntoConstraints" value="NO"/>
  23.213                                                              </userDefinedRuntimeAttributes>
  23.214 -                                                        </imageView>
  23.215 -                                                        <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" fixedFrame="YES" insetsLayoutMarginsFromSafeArea="NO" image="pEp-status-yellow" translatesAutoresizingMaskIntoConstraints="NO" id="m0u-Jn-mQU">
  23.216 -                                                            <rect key="frame" x="15" y="15" width="20" height="20"/>
  23.217 -                                                            <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
  23.218 -                                                            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
  23.219 -                                                            <userDefinedRuntimeAttributes>
  23.220 -                                                                <userDefinedRuntimeAttribute type="boolean" keyPath="translatesAutoresizingMaskIntoConstraints" value="NO"/>
  23.221 -                                                            </userDefinedRuntimeAttributes>
  23.222 -                                                        </imageView>
  23.223 +                                                        </view>
  23.224                                                      </subviews>
  23.225                                                      <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
  23.226                                                      <constraints>
  23.227 -                                                        <constraint firstItem="YqR-ga-Tf9" firstAttribute="leading" secondItem="UPT-Ig-AlN" secondAttribute="leading" id="89G-HL-lBv"/>
  23.228 -                                                        <constraint firstAttribute="bottom" secondItem="YqR-ga-Tf9" secondAttribute="bottom" id="NOg-aR-jF3"/>
  23.229 -                                                        <constraint firstItem="YqR-ga-Tf9" firstAttribute="top" secondItem="UPT-Ig-AlN" secondAttribute="top" id="oJy-iG-s3V"/>
  23.230 -                                                        <constraint firstAttribute="trailing" secondItem="YqR-ga-Tf9" secondAttribute="trailing" id="vbN-gb-MVF"/>
  23.231 +                                                        <constraint firstItem="bNf-Dy-rbx" firstAttribute="trailing" secondItem="cG7-zS-ib7" secondAttribute="trailing" id="1kX-7Z-Wp1"/>
  23.232 +                                                        <constraint firstItem="KTi-T9-Inm" firstAttribute="leading" secondItem="wra-Ql-iZp" secondAttribute="trailing" constant="10" id="2Q8-nB-uOr"/>
  23.233 +                                                        <constraint firstItem="bNf-Dy-rbx" firstAttribute="leading" secondItem="ha5-Vd-x3U" secondAttribute="trailing" constant="3" id="2sZ-lc-cQ9"/>
  23.234 +                                                        <constraint firstItem="cG7-zS-ib7" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="KTi-T9-Inm" secondAttribute="trailing" constant="8" id="4r1-41-t2J"/>
  23.235 +                                                        <constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="Tbi-dG-KCA" secondAttribute="bottom" constant="5" id="6KS-3J-RlV"/>
  23.236 +                                                        <constraint firstItem="Tbi-dG-KCA" firstAttribute="trailing" secondItem="cG7-zS-ib7" secondAttribute="trailing" id="6xZ-zP-beZ"/>
  23.237 +                                                        <constraint firstItem="Tbi-dG-KCA" firstAttribute="leading" secondItem="ha5-Vd-x3U" secondAttribute="leading" id="7RK-nG-z25"/>
  23.238 +                                                        <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="80" id="8Jk-1U-d4g"/>
  23.239 +                                                        <constraint firstItem="ha5-Vd-x3U" firstAttribute="top" secondItem="KTi-T9-Inm" secondAttribute="bottom" constant="4" id="AcE-gd-F4j"/>
  23.240 +                                                        <constraint firstItem="Tbi-dG-KCA" firstAttribute="top" secondItem="ha5-Vd-x3U" secondAttribute="bottom" constant="4" id="EWr-iZ-sou"/>
  23.241 +                                                        <constraint firstItem="wra-Ql-iZp" firstAttribute="centerY" secondItem="QAL-Vw-DX8" secondAttribute="centerY" id="NYO-5O-s1e"/>
  23.242 +                                                        <constraint firstItem="KTi-T9-Inm" firstAttribute="top" secondItem="QAL-Vw-DX8" secondAttribute="top" constant="5" id="UNc-1Y-dmh"/>
  23.243 +                                                        <constraint firstItem="wra-Ql-iZp" firstAttribute="leading" secondItem="QAL-Vw-DX8" secondAttribute="leading" constant="8" id="Zk3-pH-lWx"/>
  23.244 +                                                        <constraint firstItem="bNf-Dy-rbx" firstAttribute="top" secondItem="cG7-zS-ib7" secondAttribute="bottom" constant="8" id="qZO-Ed-KJB"/>
  23.245 +                                                        <constraint firstAttribute="trailing" secondItem="cG7-zS-ib7" secondAttribute="trailing" constant="8" id="w3K-mr-2DF"/>
  23.246 +                                                        <constraint firstItem="ha5-Vd-x3U" firstAttribute="leading" secondItem="KTi-T9-Inm" secondAttribute="leading" id="xlw-MY-AJ5"/>
  23.247 +                                                        <constraint firstItem="KTi-T9-Inm" firstAttribute="bottom" secondItem="cG7-zS-ib7" secondAttribute="bottom" id="yAV-Kr-YrE"/>
  23.248                                                      </constraints>
  23.249 -                                                    <userDefinedRuntimeAttributes>
  23.250 -                                                        <userDefinedRuntimeAttribute type="boolean" keyPath="translatesAutoresizingMaskIntoConstraints" value="NO"/>
  23.251 -                                                    </userDefinedRuntimeAttributes>
  23.252                                                  </view>
  23.253                                              </subviews>
  23.254 -                                            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
  23.255                                              <constraints>
  23.256 -                                                <constraint firstItem="tWZ-jW-sUg" firstAttribute="leading" secondItem="UPT-Ig-AlN" secondAttribute="trailing" constant="10" id="5wE-p5-M3j"/>
  23.257 -                                                <constraint firstItem="UPT-Ig-AlN" firstAttribute="centerY" secondItem="id9-ga-Yy6" secondAttribute="centerY" id="7c0-om-zpn"/>
  23.258 -                                                <constraint firstItem="BvI-Zi-zU6" firstAttribute="trailing" secondItem="8QD-qP-0hS" secondAttribute="trailing" id="Ari-gf-dnZ"/>
  23.259 -                                                <constraint firstItem="8QD-qP-0hS" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="tWZ-jW-sUg" secondAttribute="trailing" constant="8" id="FCP-Gf-ws2"/>
  23.260 -                                                <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="80" id="Fjj-lj-oAH"/>
  23.261 -                                                <constraint firstAttribute="trailing" secondItem="8QD-qP-0hS" secondAttribute="trailing" constant="8" id="KDc-S9-BfG"/>
  23.262 -                                                <constraint firstItem="5Py-55-oem" firstAttribute="leading" secondItem="tWZ-jW-sUg" secondAttribute="leading" id="KGf-kA-gVS"/>
  23.263 -                                                <constraint firstItem="UPT-Ig-AlN" firstAttribute="leading" secondItem="id9-ga-Yy6" secondAttribute="leading" constant="8" id="Kwq-ot-H9i"/>
  23.264 -                                                <constraint firstItem="MZJ-bg-Dw7" firstAttribute="trailing" secondItem="8QD-qP-0hS" secondAttribute="trailing" id="Nra-mU-9kx"/>
  23.265 -                                                <constraint firstItem="MZJ-bg-Dw7" firstAttribute="top" secondItem="8QD-qP-0hS" secondAttribute="bottom" constant="8" id="W09-Xa-Qin"/>
  23.266 -                                                <constraint firstItem="BvI-Zi-zU6" firstAttribute="top" secondItem="5Py-55-oem" secondAttribute="bottom" constant="4" id="Ymq-ad-cdD"/>
  23.267 -                                                <constraint firstItem="5Py-55-oem" firstAttribute="top" secondItem="tWZ-jW-sUg" secondAttribute="bottom" constant="4" id="dyB-LY-dAR"/>
  23.268 -                                                <constraint firstItem="MZJ-bg-Dw7" firstAttribute="leading" secondItem="5Py-55-oem" secondAttribute="trailing" constant="3" id="fZR-QV-Zi9"/>
  23.269 -                                                <constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="BvI-Zi-zU6" secondAttribute="bottom" constant="5" id="lBT-Xg-QNF"/>
  23.270 -                                                <constraint firstItem="tWZ-jW-sUg" firstAttribute="bottom" secondItem="8QD-qP-0hS" secondAttribute="bottom" id="lmu-KO-CeV"/>
  23.271 -                                                <constraint firstItem="tWZ-jW-sUg" firstAttribute="top" secondItem="id9-ga-Yy6" secondAttribute="top" constant="5" id="prK-py-IfZ"/>
  23.272 -                                                <constraint firstItem="BvI-Zi-zU6" firstAttribute="leading" secondItem="5Py-55-oem" secondAttribute="leading" id="tRf-eY-RHH"/>
  23.273 +                                                <constraint firstItem="QAL-Vw-DX8" firstAttribute="leading" secondItem="DUw-sX-YAB" secondAttribute="leading" constant="5" id="JTB-YD-EVR"/>
  23.274 +                                                <constraint firstAttribute="bottom" secondItem="QAL-Vw-DX8" secondAttribute="bottom" id="h0v-32-gE0"/>
  23.275 +                                                <constraint firstAttribute="trailing" secondItem="QAL-Vw-DX8" secondAttribute="trailing" constant="5" id="hCS-P8-iNQ"/>
  23.276 +                                                <constraint firstItem="QAL-Vw-DX8" firstAttribute="top" secondItem="DUw-sX-YAB" secondAttribute="top" id="zCJ-3M-EJk"/>
  23.277                                              </constraints>
  23.278 -                                        </view>
  23.279 -                                    </subviews>
  23.280 -                                    <constraints>
  23.281 -                                        <constraint firstAttribute="bottom" secondItem="id9-ga-Yy6" secondAttribute="bottom" id="N06-Fr-Vmu"/>
  23.282 -                                        <constraint firstItem="id9-ga-Yy6" firstAttribute="top" secondItem="jgQ-nZ-h1r" secondAttribute="top" id="Yfr-Lm-bxw"/>
  23.283 -                                        <constraint firstItem="id9-ga-Yy6" firstAttribute="leading" secondItem="jgQ-nZ-h1r" secondAttribute="leading" constant="5" id="h3X-97-D9m"/>
  23.284 -                                        <constraint firstAttribute="trailing" secondItem="id9-ga-Yy6" secondAttribute="trailing" constant="5" id="k3z-9G-pVO"/>
  23.285 -                                    </constraints>
  23.286 -                                </tableViewCellContentView>
  23.287 -                                <connections>
  23.288 -                                    <outlet property="addressLabel" destination="tWZ-jW-sUg" id="4xO-Zs-PDB"/>
  23.289 -                                    <outlet property="attachmentIcon" destination="3BC-6k-zL0" id="ZMO-5d-OGj"/>
  23.290 -                                    <outlet property="contactImageView" destination="YqR-ga-Tf9" id="E2c-EP-D1U"/>
  23.291 -                                    <outlet property="dateLabel" destination="Wkg-wf-Dbd" id="TSP-tH-GR2"/>
  23.292 -                                    <outlet property="flaggedImageView" destination="BLq-0g-OgR" id="a6H-Fv-kDq"/>
  23.293 -                                    <outlet property="ratingImage" destination="m0u-Jn-mQU" id="Xod-5v-9K3"/>
  23.294 -                                    <outlet property="subjectLabel" destination="5Py-55-oem" id="UtV-Po-SPg"/>
  23.295 -                                    <outlet property="summaryLabel" destination="BvI-Zi-zU6" id="oGG-8D-EeC"/>
  23.296 -                                </connections>
  23.297 -                            </tableViewCell>
  23.298 -                        </prototypes>
  23.299 -                        <connections>
  23.300 -                            <outlet property="dataSource" destination="kcA-RK-9Xg" id="IAG-qJ-l6e"/>
  23.301 -                            <outlet property="delegate" destination="kcA-RK-9Xg" id="Urv-Qr-ajf"/>
  23.302 -                        </connections>
  23.303 -                    </tableView>
  23.304 +                                        </tableViewCellContentView>
  23.305 +                                        <connections>
  23.306 +                                            <outlet property="addressLabel" destination="KTi-T9-Inm" id="jAS-qW-dzp"/>
  23.307 +                                            <outlet property="attachmentIcon" destination="qYK-Q0-GO5" id="6ih-R7-GT9"/>
  23.308 +                                            <outlet property="contactImageView" destination="ocF-vy-7Ef" id="ujJ-Jy-6p1"/>
  23.309 +                                            <outlet property="dateLabel" destination="a1D-BW-3Rd" id="gbR-pS-LqK"/>
  23.310 +                                            <outlet property="flaggedImageView" destination="hoT-RP-AkI" id="Agf-WF-8kR"/>
  23.311 +                                            <outlet property="ratingImage" destination="gja-fY-c60" id="upE-7t-pJp"/>
  23.312 +                                            <outlet property="subjectLabel" destination="ha5-Vd-x3U" id="T89-ft-3zQ"/>
  23.313 +                                            <outlet property="summaryLabel" destination="Tbi-dG-KCA" id="Mqb-EJ-M21"/>
  23.314 +                                        </connections>
  23.315 +                                    </tableViewCell>
  23.316 +                                </prototypes>
  23.317 +                            </tableView>
  23.318 +                        </subviews>
  23.319 +                        <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
  23.320 +                        <constraints>
  23.321 +                            <constraint firstItem="gL5-KI-75G" firstAttribute="trailing" secondItem="1Oj-l2-jRA" secondAttribute="trailing" id="7Aa-HN-69F"/>
  23.322 +                            <constraint firstItem="gL5-KI-75G" firstAttribute="bottom" secondItem="1Oj-l2-jRA" secondAttribute="bottom" id="BVY-Ij-lOg"/>
  23.323 +                            <constraint firstItem="1Oj-l2-jRA" firstAttribute="top" secondItem="gL5-KI-75G" secondAttribute="top" id="daB-yH-vL8"/>
  23.324 +                            <constraint firstItem="1Oj-l2-jRA" firstAttribute="leading" secondItem="gL5-KI-75G" secondAttribute="leading" id="jIi-mK-9Wc"/>
  23.325 +                        </constraints>
  23.326 +                        <viewLayoutGuide key="safeArea" id="gL5-KI-75G"/>
  23.327 +                    </view>
  23.328                      <toolbarItems>
  23.329 -                        <barButtonItem image="unread-icon" id="VEt-1N-tdD">
  23.330 +                        <barButtonItem image="unread-icon" id="qvK-qQ-Gk6" userLabel="Enable Filter Button">
  23.331                              <connections>
  23.332 -                                <action selector="filterButtonHasBeenPressed:" destination="kcA-RK-9Xg" id="FX3-N7-2dC"/>
  23.333 +                                <action selector="filterButtonHasBeenPressed:" destination="ldy-GA-D6J" id="ywQ-Ih-ND0"/>
  23.334                              </connections>
  23.335                          </barButtonItem>
  23.336 -                        <barButtonItem style="plain" systemItem="flexibleSpace" id="Ypz-yH-KbI"/>
  23.337 -                        <barButtonItem image="compose" id="u8o-KA-6lO">
  23.338 +                        <barButtonItem style="plain" systemItem="flexibleSpace" id="Syt-Kn-S3E"/>
  23.339 +                        <barButtonItem image="compose" id="uUt-t6-VUj" userLabel="Show Compose Button">
  23.340                              <connections>
  23.341 -                                <segue destination="NY2-HI-4ou" kind="presentation" identifier="segueCompose" id="6vv-Jr-8Nm"/>
  23.342 +                                <segue destination="NY2-HI-4ou" kind="presentation" identifier="segueCompose" id="2Ml-4S-RYf"/>
  23.343                              </connections>
  23.344                          </barButtonItem>
  23.345                      </toolbarItems>
  23.346 -                    <navigationItem key="navigationItem" title="Inbox" id="bgm-ua-A0f">
  23.347 -                        <barButtonItem key="rightBarButtonItem" title="Edit" id="hax-OT-dfL">
  23.348 +                    <navigationItem key="navigationItem" title="Inbox" id="aP4-ia-HTP">
  23.349 +                        <barButtonItem key="rightBarButtonItem" title="Edit" id="4U1-dM-wKT">
  23.350                              <connections>
  23.351 -                                <action selector="Edit:" destination="kcA-RK-9Xg" id="vJg-7j-Icq"/>
  23.352 +                                <action selector="editButtonPressed:" destination="ldy-GA-D6J" id="Ck9-Xw-mLV"/>
  23.353                              </connections>
  23.354                          </barButtonItem>
  23.355                      </navigationItem>
  23.356 +                    <simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
  23.357                      <connections>
  23.358 -                        <outlet property="enableFilterButton" destination="VEt-1N-tdD" id="0iq-eB-HNI"/>
  23.359 -                        <segue destination="Rly-af-89k" kind="presentation" identifier="segueAddNewAccount" id="Na7-CM-lbe"/>
  23.360 -                        <segue destination="NY2-HI-4ou" kind="presentation" identifier="segueReplyAll" id="xmi-xn-p8T"/>
  23.361 -                        <segue destination="NY2-HI-4ou" kind="presentation" identifier="segueForward" id="YH0-dx-pSs"/>
  23.362 -                        <segue destination="NY2-HI-4ou" kind="presentation" identifier="segueReply" id="I15-Dm-oo1"/>
  23.363 -                        <segue destination="NY2-HI-4ou" kind="presentation" identifier="segueEditDraft" id="fJ0-cY-ZEb"/>
  23.364 -                        <segue destination="WY0-yJ-1SU" kind="presentation" identifier="segueShowMoveToFolder" id="d5O-Wk-gjZ"/>
  23.365 -                        <segue destination="lPr-gi-BrG" kind="showDetail" identifier="segueShowEmailSplitView" id="63y-AC-Fyu"/>
  23.366 -                        <segue destination="eLD-PA-Nmx" kind="showDetail" identifier="segueShowThreadedEmail" id="rUh-Ai-iWA"/>
  23.367 -                        <segue destination="nc4-kR-K9D" kind="show" identifier="segueShowFilter" id="kQS-uu-oHl"/>
  23.368 -                        <segue destination="3bx-34-vLD" kind="show" identifier="segueShowEmailNotSplitView" id="5Kn-pc-9Jc"/>
  23.369 +                        <outlet property="enableFilterButton" destination="qvK-qQ-Gk6" id="c4d-QA-utg"/>
  23.370 +                        <outlet property="tableView" destination="1Oj-l2-jRA" id="dbk-cO-CLi"/>
  23.371 +                        <segue destination="tTN-8A-7tU" kind="show" identifier="segueShowEmailNotSplitView" id="uOM-R2-1sE"/>
  23.372 +                        <segue destination="Rly-af-89k" kind="presentation" identifier="segueAddNewAccount" id="Sq5-Lx-gH6"/>
  23.373 +                        <segue destination="NY2-HI-4ou" kind="presentation" identifier="segueReplyAll" id="yAp-Cu-TCw"/>
  23.374 +                        <segue destination="NY2-HI-4ou" kind="presentation" identifier="segueForward" id="ok6-PZ-sCI"/>
  23.375 +                        <segue destination="NY2-HI-4ou" kind="presentation" identifier="segueReply" id="Bs0-pZ-8nY"/>
  23.376 +                        <segue destination="NY2-HI-4ou" kind="presentation" identifier="segueEditDraft" id="VVX-sZ-2dU"/>
  23.377 +                        <segue destination="WY0-yJ-1SU" kind="presentation" identifier="segueShowMoveToFolder" id="cRe-YG-393"/>
  23.378 +                        <segue destination="nc4-kR-K9D" kind="show" identifier="segueShowFilter" id="t4t-3T-ovM"/>
  23.379 +                        <segue destination="tTN-8A-7tU" kind="showDetail" identifier="segueShowEmailSplitView" id="HHz-at-Ehg"/>
  23.380                      </connections>
  23.381 -                </tableViewController>
  23.382 -                <placeholder placeholderIdentifier="IBFirstResponder" id="d8T-vB-XpT" userLabel="First Responder" sceneMemberID="firstResponder"/>
  23.383 +                </viewController>
  23.384 +                <placeholder placeholderIdentifier="IBFirstResponder" id="m6c-dF-C80" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
  23.385              </objects>
  23.386 -            <point key="canvasLocation" x="4237.6000000000004" y="-895.50224887556226"/>
  23.387 +            <point key="canvasLocation" x="2942" y="-1845"/>
  23.388          </scene>
  23.389          <!--Navigation Controller-->
  23.390          <scene sceneID="pH2-0g-XGV">
  23.391 @@ -218,37 +243,115 @@
  23.392                  </navigationController>
  23.393                  <placeholder placeholderIdentifier="IBFirstResponder" id="aWP-YW-F6w" userLabel="First Responder" sceneMemberID="firstResponder"/>
  23.394              </objects>
  23.395 -            <point key="canvasLocation" x="4490" y="-8"/>
  23.396 +            <point key="canvasLocation" x="4548" y="140"/>
  23.397          </scene>
  23.398 -        <!--Navigation Controller-->
  23.399 -        <scene sceneID="jm1-97-n5e">
  23.400 +        <!--Email Detail View Controller-->
  23.401 +        <scene sceneID="RGR-UH-VHw">
  23.402              <objects>
  23.403 -                <navigationController automaticallyAdjustsScrollViewInsets="NO" toolbarHidden="NO" id="lPr-gi-BrG" sceneMemberID="viewController">
  23.404 -                    <toolbarItems/>
  23.405 +                <viewController storyboardIdentifier="EmailDetailViewController" id="fRo-D2-Fjz" customClass="EmailDetailViewController" customModule="pEpForiOS" customModuleProvider="target" sceneMemberID="viewController">
  23.406 +                    <view key="view" contentMode="scaleToFill" id="JE8-0O-ekz">
  23.407 +                        <rect key="frame" x="0.0" y="0.0" width="375" height="574"/>
  23.408 +                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
  23.409 +                        <subviews>
  23.410 +                            <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" pagingEnabled="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" bouncesZoom="NO" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="HP3-Sj-MgZ">
  23.411 +                                <rect key="frame" x="0.0" y="0.0" width="375" height="574"/>
  23.412 +                                <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
  23.413 +                                <collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="0.0" minimumInteritemSpacing="0.0" id="LwL-nB-lHm">
  23.414 +                                    <size key="itemSize" width="50" height="50"/>
  23.415 +                                    <size key="headerReferenceSize" width="0.0" height="0.0"/>
  23.416 +                                    <size key="footerReferenceSize" width="0.0" height="0.0"/>
  23.417 +                                    <inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
  23.418 +                                </collectionViewFlowLayout>
  23.419 +                                <cells>
  23.420 +                                    <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" reuseIdentifier="XIB used - do not instantiate" id="kIE-Eq-O7W">
  23.421 +                                        <rect key="frame" x="0.0" y="-38.5" width="375" height="651"/>
  23.422 +                                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
  23.423 +                                        <collectionViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="tKR-Vh-qyF">
  23.424 +                                            <rect key="frame" x="0.0" y="0.0" width="375" height="651"/>
  23.425 +                                            <autoresizingMask key="autoresizingMask"/>
  23.426 +                                            <color key="backgroundColor" systemColor="systemGreenColor" red="0.20392156859999999" green="0.78039215689999997" blue="0.34901960780000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
  23.427 +                                        </collectionViewCellContentView>
  23.428 +                                        <size key="customSize" width="375" height="651"/>
  23.429 +                                    </collectionViewCell>
  23.430 +                                </cells>
  23.431 +                            </collectionView>
  23.432 +                        </subviews>
  23.433 +                        <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
  23.434 +                        <constraints>
  23.435 +                            <constraint firstItem="Bie-ml-VZ0" firstAttribute="trailing" secondItem="HP3-Sj-MgZ" secondAttribute="trailing" id="9mB-JZ-MRy"/>
  23.436 +                            <constraint firstItem="HP3-Sj-MgZ" firstAttribute="top" secondItem="Bie-ml-VZ0" secondAttribute="top" id="AU6-e6-oDf"/>
  23.437 +                            <constraint firstItem="Bie-ml-VZ0" firstAttribute="bottom" secondItem="HP3-Sj-MgZ" secondAttribute="bottom" id="Gcc-f9-Fhp"/>
  23.438 +                            <constraint firstItem="HP3-Sj-MgZ" firstAttribute="leading" secondItem="Bie-ml-VZ0" secondAttribute="leading" id="utt-jH-r7F"/>
  23.439 +                        </constraints>
  23.440 +                        <viewLayoutGuide key="safeArea" id="Bie-ml-VZ0"/>
  23.441 +                    </view>
  23.442 +                    <extendedEdge key="edgesForExtendedLayout"/>
  23.443 +                    <toolbarItems>
  23.444 +                        <barButtonItem image="icon-unflagged" id="eWC-Rq-MJm" userLabel="Flag">
  23.445 +                            <connections>
  23.446 +                                <action selector="flagButtonPressed:" destination="fRo-D2-Fjz" id="B8k-7M-BGc"/>
  23.447 +                            </connections>
  23.448 +                        </barButtonItem>
  23.449 +                        <barButtonItem style="plain" systemItem="flexibleSpace" id="jm4-3w-I3N"/>
  23.450 +                        <barButtonItem image="folders-icon-folder" id="Zlf-LL-yLH" userLabel="Move to Folder">
  23.451 +                            <connections>
  23.452 +                                <action selector="moveToFolderButtonPressed:" destination="fRo-D2-Fjz" id="b20-nd-RSu"/>
  23.453 +                            </connections>
  23.454 +                        </barButtonItem>
  23.455 +                        <barButtonItem style="plain" systemItem="flexibleSpace" id="uWS-vB-hh8"/>
  23.456 +                        <barButtonItem image="folders-icon-trash" id="zPY-ag-aQd" userLabel="destructive item">
  23.457 +                            <connections>
  23.458 +                                <action selector="destructiveButtonPressed:" destination="fRo-D2-Fjz" id="UIg-Zz-5bT"/>
  23.459 +                            </connections>
  23.460 +                        </barButtonItem>
  23.461 +                        <barButtonItem style="plain" systemItem="flexibleSpace" id="akv-wk-ycl"/>
  23.462 +                        <barButtonItem image="reply" id="OL8-wT-4Rt" userLabel="reply item">
  23.463 +                            <connections>
  23.464 +                                <action selector="replyButtonPressed:" destination="fRo-D2-Fjz" id="0ah-jt-IS7"/>
  23.465 +                            </connections>
  23.466 +                        </barButtonItem>
  23.467 +                    </toolbarItems>
  23.468 +                    <navigationItem key="navigationItem" id="x3Y-Mc-0bu">
  23.469 +                        <rightBarButtonItems>
  23.470 +                            <barButtonItem image="arrow-lft-active" id="4R9-FK-LNX" userLabel="next">
  23.471 +                                <connections>
  23.472 +                                    <action selector="nextButtonPressed:" destination="fRo-D2-Fjz" id="nL5-r5-egL"/>
  23.473 +                                </connections>
  23.474 +                            </barButtonItem>
  23.475 +                            <barButtonItem image="arrow-rgt-active" id="uhj-ab-NtG" userLabel="previous">
  23.476 +                                <connections>
  23.477 +                                    <action selector="previousButtonPressed:" destination="fRo-D2-Fjz" id="K3n-l9-U40"/>
  23.478 +                                </connections>
  23.479 +                            </barButtonItem>
  23.480 +                        </rightBarButtonItems>
  23.481 +                    </navigationItem>
  23.482                      <simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
  23.483 -                    <navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="z4A-BC-Lg4">
  23.484 -                        <rect key="frame" x="0.0" y="0.0" width="375" height="56"/>
  23.485 -                        <autoresizingMask key="autoresizingMask"/>
  23.486 -                    </navigationBar>
  23.487 -                    <nil name="viewControllers"/>
  23.488 -                    <toolbar key="toolbar" opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" translucent="NO" id="6WO-dJ-eVW">
  23.489 -                        <rect key="frame" x="0.0" y="603" width="375" height="44"/>
  23.490 -                        <autoresizingMask key="autoresizingMask"/>
  23.491 -                    </toolbar>
  23.492                      <connections>
  23.493 -                        <segue destination="3bx-34-vLD" kind="relationship" relationship="rootViewController" id="ber-OQ-S16"/>
  23.494 +                        <outlet property="collectionView" destination="HP3-Sj-MgZ" id="ar9-Hu-K2J"/>
  23.495 +                        <outlet property="destructiveButton" destination="zPY-ag-aQd" id="MFb-Va-h9a"/>
  23.496 +                        <outlet property="flagButton" destination="eWC-Rq-MJm" id="Fha-Mh-JQz"/>
  23.497 +                        <outlet property="moveToFolderButton" destination="Zlf-LL-yLH" id="z3R-Zj-R96"/>
  23.498 +                        <outlet property="nextButton" destination="4R9-FK-LNX" id="XRa-Kx-g3q"/>
  23.499 +                        <outlet property="previousButton" destination="uhj-ab-NtG" id="lE3-hB-5GJ"/>
  23.500 +                        <outlet property="replyButton" destination="OL8-wT-4Rt" id="BiN-bh-B2V"/>
  23.501 +                        <segue destination="NY2-HI-4ou" kind="presentation" identifier="segueReplyFrom" id="6by-Pi-xWQ"/>
  23.502 +                        <segue destination="NY2-HI-4ou" kind="presentation" identifier="segueReplyAllForm" id="r2P-Ra-zWf"/>
  23.503 +                        <segue destination="NY2-HI-4ou" kind="presentation" identifier="segueForward" id="0Yg-lj-kVR"/>
  23.504 +                        <segue destination="WY0-yJ-1SU" kind="presentation" identifier="segueShowMoveToFolder" id="g1q-wK-tff"/>
  23.505 +                        <segue destination="Dbs-KG-RkX" kind="presentation" identifier="segueHandshake" id="CKh-jT-ski"/>
  23.506 +                        <segue destination="Dbs-KG-RkX" kind="presentation" identifier="segueHandshakeCollapsed" id="Gcx-48-ZRF"/>
  23.507                      </connections>
  23.508 -                </navigationController>
  23.509 -                <placeholder placeholderIdentifier="IBFirstResponder" id="tPk-q9-Yzh" userLabel="First Responder" sceneMemberID="firstResponder"/>
  23.510 +                </viewController>
  23.511 +                <placeholder placeholderIdentifier="IBFirstResponder" id="NqX-Lg-wmy" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
  23.512              </objects>
  23.513 -            <point key="canvasLocation" x="4238" y="-1722"/>
  23.514 +            <point key="canvasLocation" x="3004" y="-22"/>
  23.515          </scene>
  23.516          <!--Filter Table View Controller-->
  23.517          <scene sceneID="9dD-N3-Mae">
  23.518              <objects>
  23.519                  <tableViewController id="nc4-kR-K9D" customClass="FilterTableViewController" customModule="pEpForiOS" customModuleProvider="target" sceneMemberID="viewController">
  23.520                      <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="TcR-RD-7eo">
  23.521 -                        <rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
  23.522 +                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
  23.523                          <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
  23.524                          <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
  23.525                          <prototypes>
  23.526 @@ -266,17 +369,18 @@
  23.527                              <outlet property="delegate" destination="nc4-kR-K9D" id="Kco-YV-yOE"/>
  23.528                          </connections>
  23.529                      </tableView>
  23.530 +                    <navigationItem key="navigationItem" id="643-yM-uLa"/>
  23.531                  </tableViewController>
  23.532                  <placeholder placeholderIdentifier="IBFirstResponder" id="RS6-O5-yYy" userLabel="First Responder" sceneMemberID="firstResponder"/>
  23.533              </objects>
  23.534 -            <point key="canvasLocation" x="3806" y="-7"/>
  23.535 +            <point key="canvasLocation" x="1726" y="-789"/>
  23.536          </scene>
  23.537          <!--Show email-->
  23.538          <scene sceneID="fxT-br-VYt">
  23.539              <objects>
  23.540 -                <tableViewController storyboardIdentifier="emailDetail" title="Show email" id="3bx-34-vLD" customClass="EmailViewController" customModule="pEpForiOS" customModuleProvider="target" sceneMemberID="viewController">
  23.541 +                <tableViewController storyboardIdentifier="EmailViewController" title="Show email" id="3bx-34-vLD" customClass="EmailViewController" customModule="pEpForiOS" customModuleProvider="target" sceneMemberID="viewController">
  23.542                      <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" id="mYV-vz-wEb">
  23.543 -                        <rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
  23.544 +                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
  23.545                          <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
  23.546                          <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
  23.547                          <prototypes>
  23.548 @@ -409,7 +513,7 @@
  23.549                                              <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
  23.550                                              <fontDescription key="fontDescription" type="system" pointSize="14"/>
  23.551                                              <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
  23.552 -                                            <dataDetectorType key="dataDetectorTypes" phoneNumber="YES" link="YES" address="YES" calendarEvent="YES" shipmentTrackingNumber="YES"/>
  23.553 +                                            <dataDetectorType key="dataDetectorTypes" phoneNumber="YES" link="YES" address="YES" calendarEvent="YES" shipmentTrackingNumber="YES" flightNumber="YES"/>
  23.554                                              <userDefinedRuntimeAttributes>
  23.555                                                  <userDefinedRuntimeAttribute type="rect" keyPath="textContainerInset">
  23.556                                                      <rect key="value" x="0.0" y="0.0" width="0.0" height="0.0"/>
  23.557 @@ -461,68 +565,20 @@
  23.558                          </connections>
  23.559                      </tableView>
  23.560                      <extendedEdge key="edgesForExtendedLayout" bottom="YES"/>
  23.561 -                    <toolbarItems>
  23.562 -                        <barButtonItem image="icon-unflagged" id="bej-eI-LgY" userLabel="Flag">
  23.563 -                            <connections>
  23.564 -                                <action selector="flagButtonTapped:" destination="3bx-34-vLD" id="bHB-Of-ApR"/>
  23.565 -                            </connections>
  23.566 -                        </barButtonItem>
  23.567 -                        <barButtonItem style="plain" systemItem="flexibleSpace" id="NHr-Sb-8Of"/>
  23.568 -                        <barButtonItem image="folders-icon-folder" id="a2r-iQ-NVT" userLabel="Move to Folder">
  23.569 -                            <connections>
  23.570 -                                <action selector="moveToFolderButtonTapped:" destination="3bx-34-vLD" id="Pfz-xE-sJb"/>
  23.571 -                            </connections>
  23.572 -                        </barButtonItem>
  23.573 -                        <barButtonItem style="plain" systemItem="flexibleSpace" id="pDp-Ex-gb9"/>
  23.574 -                        <barButtonItem image="folders-icon-trash" id="Swu-yi-LdI">
  23.575 -                            <connections>
  23.576 -                                <action selector="deleteButtonTapped:" destination="3bx-34-vLD" id="1i5-fP-wma"/>
  23.577 -                            </connections>
  23.578 -                        </barButtonItem>
  23.579 -                        <barButtonItem style="plain" systemItem="flexibleSpace" id="CmV-4s-3jw"/>
  23.580 -                        <barButtonItem image="reply" id="qxE-Vd-QoS">
  23.581 -                            <connections>
  23.582 -                                <action selector="pressReply:" destination="3bx-34-vLD" id="KDm-Or-31Y"/>
  23.583 -                            </connections>
  23.584 -                        </barButtonItem>
  23.585 -                    </toolbarItems>
  23.586 -                    <navigationItem key="navigationItem" id="PAv-Od-zv3">
  23.587 -                        <rightBarButtonItems>
  23.588 -                            <barButtonItem image="arrow-lft-active" id="nCS-Wg-ZJI">
  23.589 -                                <color key="tintColor" white="1" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
  23.590 -                                <connections>
  23.591 -                                    <action selector="next:" destination="3bx-34-vLD" id="dke-KM-1xj"/>
  23.592 -                                </connections>
  23.593 -                            </barButtonItem>
  23.594 -                            <barButtonItem image="arrow-rgt-active" id="NsK-Ye-A0p">
  23.595 -                                <color key="tintColor" white="1" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
  23.596 -                                <connections>
  23.597 -                                    <action selector="previous:" destination="3bx-34-vLD" id="nIJ-v6-9HL"/>
  23.598 -                                </connections>
  23.599 -                            </barButtonItem>
  23.600 -                        </rightBarButtonItems>
  23.601 -                    </navigationItem>
  23.602 +                    <toolbarItems/>
  23.603                      <simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
  23.604                      <connections>
  23.605 -                        <outlet property="destructiveButton" destination="Swu-yi-LdI" id="RX6-Nq-DS2"/>
  23.606 -                        <outlet property="flagButton" destination="bej-eI-LgY" id="Geb-Es-y6z"/>
  23.607 -                        <outlet property="moveToFolderButton" destination="a2r-iQ-NVT" id="jbS-XR-DJ5"/>
  23.608 -                        <outlet property="nextMessage" destination="nCS-Wg-ZJI" id="Q0q-LK-Q5C"/>
  23.609 -                        <outlet property="previousMessage" destination="NsK-Ye-A0p" id="tHt-Ag-IaU"/>
  23.610 -                        <outlet property="replyButton" destination="qxE-Vd-QoS" id="cwp-Ig-BVT"/>
  23.611                          <segue destination="NY2-HI-4ou" kind="presentation" identifier="segueReplyFrom" id="Usl-iS-7fo"/>
  23.612                          <segue destination="NY2-HI-4ou" kind="presentation" identifier="segueReplyAllForm" id="1zD-EW-3fN"/>
  23.613                          <segue destination="NY2-HI-4ou" kind="presentation" identifier="segueForward" id="2fD-kL-Bvj"/>
  23.614                          <segue destination="WY0-yJ-1SU" kind="presentation" identifier="segueShowMoveToFolder" modalPresentationStyle="pageSheet" id="RTR-We-Kc1"/>
  23.615 -                        <segue destination="Adk-MD-apd" kind="unwind" identifier="unwindToThread" unwindAction="segueUnwindEmailDisplayDoneWithSegue:" id="eRi-pR-kLP"/>
  23.616                          <segue destination="Dbs-KG-RkX" kind="presentation" identifier="segueHandshake" modalPresentationStyle="automatic" id="mZj-Mg-VzM"/>
  23.617                          <segue destination="Dbs-KG-RkX" kind="presentation" identifier="segueHandshakeCollapsed" modalPresentationStyle="fullScreen" id="0zl-tV-6Kr"/>
  23.618                      </connections>
  23.619                  </tableViewController>
  23.620                  <placeholder placeholderIdentifier="IBFirstResponder" id="C92-OM-qzy" userLabel="First Responder" sceneMemberID="firstResponder"/>
  23.621 -                <exit id="Adk-MD-apd" userLabel="Exit" sceneMemberID="exit"/>
  23.622              </objects>
  23.623 -            <point key="canvasLocation" x="5327" y="-860"/>
  23.624 +            <point key="canvasLocation" x="4756" y="-985"/>
  23.625          </scene>
  23.626          <!--Move to Account-->
  23.627          <scene sceneID="Rib-YI-OIO">
  23.628 @@ -611,6 +667,7 @@
  23.629                              <outlet property="delegate" destination="Vsb-3P-98q" id="36t-5U-9LK"/>
  23.630                          </connections>
  23.631                      </tableView>
  23.632 +                    <navigationItem key="navigationItem" id="FQE-HR-EGc"/>
  23.633                  </tableViewController>
  23.634                  <placeholder placeholderIdentifier="IBFirstResponder" id="kgu-MG-u22" userLabel="First Responder" sceneMemberID="firstResponder"/>
  23.635              </objects>
  23.636 @@ -622,15 +679,17 @@
  23.637                  <viewControllerPlaceholder storyboardName="Handshake" id="Dbs-KG-RkX" sceneMemberID="viewController"/>
  23.638                  <placeholder placeholderIdentifier="IBFirstResponder" id="Vev-AJ-nPB" userLabel="First Responder" sceneMemberID="firstResponder"/>
  23.639              </objects>
  23.640 -            <point key="canvasLocation" x="6101" y="-393"/>
  23.641 +            <point key="canvasLocation" x="5522" y="-470"/>
  23.642          </scene>
  23.643          <!--AccountCreation-->
  23.644          <scene sceneID="0vj-GL-XbM">
  23.645              <objects>
  23.646 -                <viewControllerPlaceholder storyboardName="AccountCreation" id="Rly-af-89k" sceneMemberID="viewController"/>
  23.647 +                <viewControllerPlaceholder storyboardName="AccountCreation" id="Rly-af-89k" sceneMemberID="viewController">
  23.648 +                    <navigationItem key="navigationItem" id="rSE-26-sLx"/>
  23.649 +                </viewControllerPlaceholder>
  23.650                  <placeholder placeholderIdentifier="IBFirstResponder" id="QLV-3R-1jF" userLabel="First Responder" sceneMemberID="firstResponder"/>
  23.651              </objects>
  23.652 -            <point key="canvasLocation" x="4702" y="-1411"/>
  23.653 +            <point key="canvasLocation" x="4834" y="-1476"/>
  23.654          </scene>
  23.655          <!--Navigation Controller-->
  23.656          <scene sceneID="fa0-aU-9j8">
  23.657 @@ -888,6 +947,27 @@
  23.658              </objects>
  23.659              <point key="canvasLocation" x="5252" y="833"/>
  23.660          </scene>
  23.661 +        <!--Email List Navigation View Controller-->
  23.662 +        <scene sceneID="MZI-Ie-O3U">
  23.663 +            <objects>
  23.664 +                <navigationController storyboardIdentifier="EmailListNavigationViewController" toolbarHidden="NO" id="whh-KX-6ih" customClass="EmailListNavigationViewController" sceneMemberID="viewController">
  23.665 +                    <simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
  23.666 +                    <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="saS-nD-pye">
  23.667 +                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
  23.668 +                        <autoresizingMask key="autoresizingMask"/>
  23.669 +                    </navigationBar>
  23.670 +                    <toolbar key="toolbar" opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="44P-as-CSR">
  23.671 +                        <rect key="frame" x="0.0" y="623" width="375" height="44"/>
  23.672 +                        <autoresizingMask key="autoresizingMask"/>
  23.673 +                    </toolbar>
  23.674 +                    <connections>
  23.675 +                        <segue destination="ldy-GA-D6J" kind="relationship" relationship="rootViewController" id="0mb-3K-5Pd"/>
  23.676 +                    </connections>
  23.677 +                </navigationController>
  23.678 +                <placeholder placeholderIdentifier="IBFirstResponder" id="e7d-28-DBt" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
  23.679 +            </objects>
  23.680 +            <point key="canvasLocation" x="2942" y="-2591"/>
  23.681 +        </scene>
  23.682      </scenes>
  23.683      <resources>
  23.684          <image name="arrow-lft-active" width="10" height="18"/>
  23.685 @@ -904,9 +984,9 @@
  23.686          <image name="unread-icon" width="25" height="25"/>
  23.687      </resources>
  23.688      <inferredMetricsTieBreakers>
  23.689 -        <segue reference="d5O-Wk-gjZ"/>
  23.690 -        <segue reference="JbP-D9-Vpg"/>
  23.691 -        <segue reference="5Kn-pc-9Jc"/>
  23.692 -        <segue reference="6vv-Jr-8Nm"/>
  23.693 +        <segue reference="RTR-We-Kc1"/>
  23.694 +        <segue reference="0zl-tV-6Kr"/>
  23.695 +        <segue reference="1zD-EW-3fN"/>
  23.696 +        <segue reference="HHz-at-Ehg"/>
  23.697      </inferredMetricsTieBreakers>
  23.698  </document>
    24.1 --- a/pEpForiOS/Base.lproj/NothingSelected.storyboard	Fri Feb 07 12:29:26 2020 +0100
    24.2 +++ b/pEpForiOS/Base.lproj/NothingSelected.storyboard	Fri Feb 07 12:31:01 2020 +0100
    24.3 @@ -3,7 +3,7 @@
    24.4      <device id="retina6_1" orientation="portrait" appearance="light"/>
    24.5      <dependencies>
    24.6          <deployment identifier="iOS"/>
    24.7 -        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15509"/>
    24.8 +        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15510"/>
    24.9          <capability name="Safe area layout guides" minToolsVersion="9.0"/>
   24.10          <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
   24.11      </dependencies>
   24.12 @@ -16,8 +16,8 @@
   24.13                          <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
   24.14                          <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
   24.15                          <subviews>
   24.16 -                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Storyboard" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Rk5-l1-Vt8">
   24.17 -                                <rect key="frame" x="152" y="434" width="110" height="28"/>
   24.18 +                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Nothing Selected" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Rk5-l1-Vt8">
   24.19 +                                <rect key="frame" x="121" y="434" width="172" height="28"/>
   24.20                                  <fontDescription key="fontDescription" type="system" pointSize="23"/>
   24.21                                  <color key="textColor" red="0.48627450979999998" green="0.54901960780000003" blue="0.56078431370000004" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
   24.22                                  <nil key="highlightedColor"/>
   24.23 @@ -43,10 +43,10 @@
   24.24              </objects>
   24.25              <point key="canvasLocation" x="5420" y="-1649.3253373313344"/>
   24.26          </scene>
   24.27 -        <!--emailDetail-->
   24.28 +        <!--EmailViewController-->
   24.29          <scene sceneID="ac7-WH-duf">
   24.30              <objects>
   24.31 -                <viewControllerPlaceholder storyboardIdentifier="emailDetail" storyboardName="Main" referencedIdentifier="emailDetail" id="gnv-QF-y1k" sceneMemberID="viewController"/>
   24.32 +                <viewControllerPlaceholder storyboardIdentifier="emailDetail" storyboardName="Main" referencedIdentifier="EmailViewController" id="gnv-QF-y1k" sceneMemberID="viewController"/>
   24.33                  <placeholder placeholderIdentifier="IBFirstResponder" id="VO2-Y8-sUZ" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
   24.34              </objects>
   24.35              <point key="canvasLocation" x="5327" y="-860"/>
    25.1 --- a/pEpForiOS/Base.lproj/Settings.storyboard	Fri Feb 07 12:29:26 2020 +0100
    25.2 +++ b/pEpForiOS/Base.lproj/Settings.storyboard	Fri Feb 07 12:31:01 2020 +0100
    25.3 @@ -1,9 +1,9 @@
    25.4  <?xml version="1.0" encoding="UTF-8"?>
    25.5 -<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="cPx-YX-3ty">
    25.6 +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="cPx-YX-3ty">
    25.7      <device id="retina4_7" orientation="portrait" appearance="light"/>
    25.8      <dependencies>
    25.9          <deployment identifier="iOS"/>
   25.10 -        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15510"/>
   25.11 +        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
   25.12          <capability name="Safe area layout guides" minToolsVersion="9.0"/>
   25.13          <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
   25.14      </dependencies>
   25.15 @@ -126,12 +126,13 @@
   25.16                          <segue destination="cMW-fr-EKn" kind="showDetail" identifier="segueSetOwnKey" id="D3B-Zt-U43"/>
   25.17                          <segue destination="4fP-ku-UtU" kind="showDetail" identifier="segueExtraKeys" id="DPP-UI-qfC"/>
   25.18                          <segue destination="tfJ-nw-QBg" kind="showDetail" identifier="ResetTrust" id="sr5-ig-b4W"/>
   25.19 +                        <segue destination="ubf-gx-0YH" kind="showDetail" identifier="seguePerAccountSync" id="PVg-TR-Zzb"/>
   25.20                      </connections>
   25.21                  </tableViewController>
   25.22                  <placeholder placeholderIdentifier="IBFirstResponder" id="BPe-Zm-lKR" userLabel="First Responder" sceneMemberID="firstResponder"/>
   25.23                  <exit id="1at-88-jou" userLabel="Exit" sceneMemberID="exit"/>
   25.24              </objects>
   25.25 -            <point key="canvasLocation" x="-1327" y="-1186"/>
   25.26 +            <point key="canvasLocation" x="-1306" y="-1214"/>
   25.27          </scene>
   25.28          <!--Extra Keys-->
   25.29          <scene sceneID="KkR-yF-e30">
   25.30 @@ -213,7 +214,7 @@
   25.31                  </viewController>
   25.32                  <placeholder placeholderIdentifier="IBFirstResponder" id="LCO-IG-Rwh" userLabel="First Responder" sceneMemberID="firstResponder"/>
   25.33              </objects>
   25.34 -            <point key="canvasLocation" x="463.19999999999999" y="-1891.304347826087"/>
   25.35 +            <point key="canvasLocation" x="511" y="-1952"/>
   25.36          </scene>
   25.37          <!--Reset Trust View Controller-->
   25.38          <scene sceneID="lLJ-n0-lb9">
   25.39 @@ -350,7 +351,7 @@
   25.40                  </viewController>
   25.41                  <placeholder placeholderIdentifier="IBFirstResponder" id="Pfo-Jp-fmH" userLabel="First Responder" sceneMemberID="firstResponder"/>
   25.42              </objects>
   25.43 -            <point key="canvasLocation" x="-475" y="-1174"/>
   25.44 +            <point key="canvasLocation" x="510" y="-1186"/>
   25.45          </scene>
   25.46          <!--Account Settings Table View Controller-->
   25.47          <scene sceneID="8yf-Dg-eGD">
   25.48 @@ -421,38 +422,9 @@
   25.49                                              </constraints>
   25.50                                          </tableViewCellContentView>
   25.51                                      </tableViewCell>
   25.52 -                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="heV-dy-ZLw">
   25.53 +                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="ha3-pb-H6q">
   25.54                                          <rect key="frame" x="0.0" y="106" width="375" height="44"/>
   25.55                                          <autoresizingMask key="autoresizingMask"/>
   25.56 -                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="heV-dy-ZLw" id="uzW-37-XhV">
   25.57 -                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
   25.58 -                                            <autoresizingMask key="autoresizingMask"/>
   25.59 -                                            <subviews>
   25.60 -                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Username:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YGG-ns-Pes">
   25.61 -                                                    <rect key="frame" x="20" y="11.5" width="84" height="21"/>
   25.62 -                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
   25.63 -                                                    <nil key="textColor"/>
   25.64 -                                                    <nil key="highlightedColor"/>
   25.65 -                                                </label>
   25.66 -                                                <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="6bk-kI-Bqc">
   25.67 -                                                    <rect key="frame" x="112" y="5" width="243" height="34"/>
   25.68 -                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
   25.69 -                                                    <textInputTraits key="textInputTraits"/>
   25.70 -                                                </textField>
   25.71 -                                            </subviews>
   25.72 -                                            <constraints>
   25.73 -                                                <constraint firstAttribute="bottom" secondItem="6bk-kI-Bqc" secondAttribute="bottom" constant="5" id="4aE-oO-4lg"/>
   25.74 -                                                <constraint firstItem="6bk-kI-Bqc" firstAttribute="top" secondItem="uzW-37-XhV" secondAttribute="top" constant="5" id="5oj-Sc-MFd"/>
   25.75 -                                                <constraint firstAttribute="trailing" secondItem="6bk-kI-Bqc" secondAttribute="trailing" constant="20" symbolic="YES" id="7qP-7J-tqp"/>
   25.76 -                                                <constraint firstItem="YGG-ns-Pes" firstAttribute="centerY" secondItem="uzW-37-XhV" secondAttribute="centerY" id="CtB-T7-W74"/>
   25.77 -                                                <constraint firstItem="YGG-ns-Pes" firstAttribute="leading" secondItem="uzW-37-XhV" secondAttribute="leading" constant="20" symbolic="YES" id="o1T-3M-dAs"/>
   25.78 -                                                <constraint firstItem="6bk-kI-Bqc" firstAttribute="leading" secondItem="YGG-ns-Pes" secondAttribute="trailing" constant="8" id="v13-om-FAp"/>
   25.79 -                                            </constraints>
   25.80 -                                        </tableViewCellContentView>
   25.81 -                                    </tableViewCell>
   25.82 -                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="ha3-pb-H6q">
   25.83 -                                        <rect key="frame" x="0.0" y="150" width="375" height="44"/>
   25.84 -                                        <autoresizingMask key="autoresizingMask"/>
   25.85                                          <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ha3-pb-H6q" id="EaS-It-0GM">
   25.86                                              <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
   25.87                                              <autoresizingMask key="autoresizingMask"/>
   25.88 @@ -479,6 +451,34 @@
   25.89                                              </constraints>
   25.90                                          </tableViewCellContentView>
   25.91                                      </tableViewCell>
   25.92 +                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="cDc-tO-miL">
   25.93 +                                        <rect key="frame" x="0.0" y="150" width="375" height="44"/>
   25.94 +                                        <autoresizingMask key="autoresizingMask"/>
   25.95 +                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="cDc-tO-miL" id="5a1-Zd-MSP">
   25.96 +                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
   25.97 +                                            <autoresizingMask key="autoresizingMask"/>
   25.98 +                                            <subviews>
   25.99 +                                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zHO-Gd-VWW">
  25.100 +                                                    <rect key="frame" x="310" y="6.5" width="51" height="31"/>
  25.101 +                                                    <connections>
  25.102 +                                                        <action selector="switchPEPSyncToggle:" destination="Eri-pJ-T3J" eventType="valueChanged" id="q6q-fw-PGh"/>
  25.103 +                                                    </connections>
  25.104 +                                                </switch>
  25.105 +                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="p≡p Sync" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Tjb-uM-eUF">
  25.106 +                                                    <rect key="frame" x="16" y="11.5" width="75" height="21"/>
  25.107 +                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
  25.108 +                                                    <nil key="textColor"/>
  25.109 +                                                    <nil key="highlightedColor"/>
  25.110 +                                                </label>
  25.111 +                                            </subviews>
  25.112 +                                            <constraints>
  25.113 +                                                <constraint firstItem="Tjb-uM-eUF" firstAttribute="leading" secondItem="5a1-Zd-MSP" secondAttribute="leadingMargin" id="3yI-49-LeI"/>
  25.114 +                                                <constraint firstItem="Tjb-uM-eUF" firstAttribute="centerY" secondItem="5a1-Zd-MSP" secondAttribute="centerY" id="7lG-kZ-bme"/>
  25.115 +                                                <constraint firstItem="zHO-Gd-VWW" firstAttribute="centerY" secondItem="5a1-Zd-MSP" secondAttribute="centerY" id="VjN-Mr-nY6"/>
  25.116 +                                                <constraint firstAttribute="trailing" secondItem="zHO-Gd-VWW" secondAttribute="trailing" constant="16" id="bk4-9q-Rsz"/>
  25.117 +                                            </constraints>
  25.118 +                                        </tableViewCellContentView>
  25.119 +                                    </tableViewCell>
  25.120                                      <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="SEz-qh-Tnn">
  25.121                                          <rect key="frame" x="0.0" y="194" width="375" height="44"/>
  25.122                                          <autoresizingMask key="autoresizingMask"/>
  25.123 @@ -613,12 +613,41 @@
  25.124                                              </constraints>
  25.125                                          </tableViewCellContentView>
  25.126                                      </tableViewCell>
  25.127 +                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="Opu-Se-iSh">
  25.128 +                                        <rect key="frame" x="0.0" y="450" width="375" height="44"/>
  25.129 +                                        <autoresizingMask key="autoresizingMask"/>
  25.130 +                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Opu-Se-iSh" id="3ju-kD-Rc2">
  25.131 +                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
  25.132 +                                            <autoresizingMask key="autoresizingMask"/>
  25.133 +                                            <subviews>
  25.134 +                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Username:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="l6l-lO-WTg">
  25.135 +                                                    <rect key="frame" x="20" y="11.5" width="84" height="21"/>
  25.136 +                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
  25.137 +                                                    <nil key="textColor"/>
  25.138 +                                                    <nil key="highlightedColor"/>
  25.139 +                                                </label>
  25.140 +                                                <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="20d-ES-uKL">
  25.141 +                                                    <rect key="frame" x="112" y="5" width="243" height="34"/>
  25.142 +                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
  25.143 +                                                    <textInputTraits key="textInputTraits"/>
  25.144 +                                                </textField>
  25.145 +                                            </subviews>
  25.146 +                                            <constraints>
  25.147 +                                                <constraint firstItem="20d-ES-uKL" firstAttribute="leading" secondItem="l6l-lO-WTg" secondAttribute="trailing" constant="8" id="G28-82-5Ie"/>
  25.148 +                                                <constraint firstItem="l6l-lO-WTg" firstAttribute="leading" secondItem="3ju-kD-Rc2" secondAttribute="leading" constant="20" symbolic="YES" id="OF2-oM-82x"/>
  25.149 +                                                <constraint firstItem="l6l-lO-WTg" firstAttribute="centerY" secondItem="3ju-kD-Rc2" secondAttribute="centerY" id="Pfv-Uh-02G"/>
  25.150 +                                                <constraint firstAttribute="trailing" secondItem="20d-ES-uKL" secondAttribute="trailing" constant="20" symbolic="YES" id="dfD-20-ZZe"/>
  25.151 +                                                <constraint firstItem="20d-ES-uKL" firstAttribute="top" secondItem="3ju-kD-Rc2" secondAttribute="top" constant="5" id="f2o-od-e2j"/>
  25.152 +                                                <constraint firstAttribute="bottom" secondItem="20d-ES-uKL" secondAttribute="bottom" constant="5" id="jMk-Dt-A8M"/>
  25.153 +                                            </constraints>
  25.154 +                                        </tableViewCellContentView>
  25.155 +                                    </tableViewCell>
  25.156                                  </cells>
  25.157                              </tableViewSection>
  25.158                              <tableViewSection id="lcp-bR-tG4">
  25.159                                  <cells>
  25.160                                      <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="uQq-jB-jvC">
  25.161 -                                        <rect key="frame" x="0.0" y="486" width="375" height="44"/>
  25.162 +                                        <rect key="frame" x="0.0" y="530" width="375" height="44"/>
  25.163                                          <autoresizingMask key="autoresizingMask"/>
  25.164                                          <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="uQq-jB-jvC" id="oxu-Hi-Kpi">
  25.165                                              <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
  25.166 @@ -647,7 +676,7 @@
  25.167                                          </tableViewCellContentView>
  25.168                                      </tableViewCell>
  25.169                                      <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="3ok-CC-12G">
  25.170 -                                        <rect key="frame" x="0.0" y="530" width="375" height="44"/>
  25.171 +                                        <rect key="frame" x="0.0" y="574" width="375" height="44"/>
  25.172                                          <autoresizingMask key="autoresizingMask"/>
  25.173                                          <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="3ok-CC-12G" id="a25-Mi-BL5">
  25.174                                              <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
  25.175 @@ -676,7 +705,7 @@
  25.176                                          </tableViewCellContentView>
  25.177                                      </tableViewCell>
  25.178                                      <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="qam-JB-sRf">
  25.179 -                                        <rect key="frame" x="0.0" y="574" width="375" height="44"/>
  25.180 +                                        <rect key="frame" x="0.0" y="618" width="375" height="44"/>
  25.181                                          <autoresizingMask key="autoresizingMask"/>
  25.182                                          <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="qam-JB-sRf" id="Cae-Xt-xQe">
  25.183                                              <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
  25.184 @@ -704,42 +733,32 @@
  25.185                                              </constraints>
  25.186                                          </tableViewCellContentView>
  25.187                                      </tableViewCell>
  25.188 -                                </cells>
  25.189 -                            </tableViewSection>
  25.190 -                            <tableViewSection headerTitle="Section-4" id="NDe-dz-nXc">
  25.191 -                                <cells>
  25.192 -                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="PhK-zR-wH7">
  25.193 -                                        <rect key="frame" x="0.0" y="674" width="375" height="44"/>
  25.194 +                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="AnE-x4-lic">
  25.195 +                                        <rect key="frame" x="0.0" y="662" width="375" height="44"/>
  25.196                                          <autoresizingMask key="autoresizingMask"/>
  25.197 -                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="PhK-zR-wH7" id="Ghb-kV-wtZ">
  25.198 +                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="AnE-x4-lic" id="fke-5P-2zb">
  25.199                                              <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
  25.200                                              <autoresizingMask key="autoresizingMask"/>
  25.201                                              <subviews>
  25.202 -                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="KeySync" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="E8I-np-XGR">
  25.203 -                                                    <rect key="frame" x="20" y="11.5" width="67" height="21"/>
  25.204 -                                                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
  25.205 +                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Username:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="RHz-qe-z44">
  25.206 +                                                    <rect key="frame" x="20" y="11.5" width="84" height="21"/>
  25.207                                                      <fontDescription key="fontDescription" type="system" pointSize="17"/>
  25.208                                                      <nil key="textColor"/>
  25.209                                                      <nil key="highlightedColor"/>
  25.210                                                  </label>
  25.211 -                                                <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="38v-V4-M3F">
  25.212 -                                                    <rect key="frame" x="351" y="5" width="4" height="34"/>
  25.213 +                                                <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="GoF-g6-pSr">
  25.214 +                                                    <rect key="frame" x="112" y="5" width="243" height="34"/>
  25.215                                                      <fontDescription key="fontDescription" type="system" pointSize="14"/>
  25.216                                                      <textInputTraits key="textInputTraits"/>
  25.217                                                  </textField>
  25.218 -                                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="MZb-TK-ECd">
  25.219 -                                                    <rect key="frame" x="308" y="6.5" width="51" height="31"/>
  25.220 -                                                    <connections>
  25.221 -                                                        <action selector="didPressPEPSyncToggle:" destination="Eri-pJ-T3J" eventType="valueChanged" id="bjg-Ed-BUN"/>
  25.222 -                                                    </connections>
  25.223 -                                                </switch>
  25.224                                              </subviews>
  25.225                                              <constraints>
  25.226 -                                                <constraint firstAttribute="trailing" secondItem="MZb-TK-ECd" secondAttribute="trailing" constant="18" id="Ca4-wU-hCI"/>
  25.227 -                                                <constraint firstItem="MZb-TK-ECd" firstAttribute="centerY" secondItem="Ghb-kV-wtZ" secondAttribute="centerY" id="Hv6-dt-4ez"/>
  25.228 -                                                <constraint firstAttribute="bottom" secondItem="38v-V4-M3F" secondAttribute="bottom" constant="5" id="UkO-zc-yQd"/>
  25.229 -                                                <constraint firstAttribute="trailing" secondItem="38v-V4-M3F" secondAttribute="trailing" constant="20" symbolic="YES" id="bov-GP-Ea2"/>
  25.230 -                                                <constraint firstItem="38v-V4-M3F" firstAttribute="top" secondItem="Ghb-kV-wtZ" secondAttribute="top" constant="5" id="pJn-Vi-N1h"/>
  25.231 +                                                <constraint firstAttribute="bottom" secondItem="GoF-g6-pSr" secondAttribute="bottom" constant="5" id="5dD-Tz-sKf"/>
  25.232 +                                                <constraint firstItem="GoF-g6-pSr" firstAttribute="leading" secondItem="RHz-qe-z44" secondAttribute="trailing" constant="8" id="DnJ-St-jq7"/>
  25.233 +                                                <constraint firstAttribute="trailing" secondItem="GoF-g6-pSr" secondAttribute="trailing" constant="20" symbolic="YES" id="Krg-Q7-S9q"/>
  25.234 +                                                <constraint firstItem="RHz-qe-z44" firstAttribute="leading" secondItem="fke-5P-2zb" secondAttribute="leading" constant="20" symbolic="YES" id="Ptl-CC-tcd"/>
  25.235 +                                                <constraint firstItem="GoF-g6-pSr" firstAttribute="top" secondItem="fke-5P-2zb" secondAttribute="top" constant="5" id="RMC-6H-ct7"/>
  25.236 +                                                <constraint firstItem="RHz-qe-z44" firstAttribute="centerY" secondItem="fke-5P-2zb" secondAttribute="centerY" id="jzR-JK-TfR"/>
  25.237                                              </constraints>
  25.238                                          </tableViewCellContentView>
  25.239                                      </tableViewCell>
  25.240 @@ -766,10 +785,10 @@
  25.241                          <outlet property="imapPortTextfield" destination="ukB-K0-MMG" id="rGA-tC-CYA"/>
  25.242                          <outlet property="imapSecurityTextfield" destination="rCJ-UW-Jmn" id="Vz4-6T-rdl"/>
  25.243                          <outlet property="imapServerTextfield" destination="LOO-6m-Q5O" id="2JT-EB-GaR"/>
  25.244 +                        <outlet property="imapUsernameTextField" destination="20d-ES-uKL" id="Jvy-ZU-ny5"/>
  25.245                          <outlet property="nameTextfield" destination="RpU-jD-tx7" id="eBg-fx-AAF"/>
  25.246                          <outlet property="oauth2ActivityIndicator" destination="tUA-ey-cn7" id="r97-xz-SfT"/>
  25.247                          <outlet property="oauth2TableViewCell" destination="Bp7-9N-v9r" id="2w0-dL-3iG"/>
  25.248 -                        <outlet property="pEpSyncToggle" destination="MZb-TK-ECd" id="wPh-5r-ozE"/>
  25.249                          <outlet property="passwordTableViewCell" destination="ha3-pb-H6q" id="hS0-M0-ZIT"/>
  25.250                          <outlet property="passwordTextfield" destination="74n-su-y4m" id="cdw-kQ-Z8v"/>
  25.251                          <outlet property="resetIdentityCell" destination="SEz-qh-Tnn" id="J9I-3b-uog"/>
  25.252 @@ -777,12 +796,13 @@
  25.253                          <outlet property="smtpPortTextfield" destination="f4i-WV-eyd" id="SWD-86-mCa"/>
  25.254                          <outlet property="smtpSecurityTextfield" destination="JLc-di-cx2" id="sqO-QP-g1u"/>
  25.255                          <outlet property="smtpServerTextfield" destination="fSa-9P-hot" id="sQi-AR-vlO"/>
  25.256 -                        <outlet property="usernameTextfield" destination="6bk-kI-Bqc" id="gVe-EG-52F"/>
  25.257 +                        <outlet property="smtpUsernameTextField" destination="GoF-g6-pSr" id="URl-UP-kJm"/>
  25.258 +                        <outlet property="switchKeySync" destination="zHO-Gd-VWW" id="lbQ-5e-DfG"/>
  25.259                      </connections>
  25.260                  </tableViewController>
  25.261                  <placeholder placeholderIdentifier="IBFirstResponder" id="2Hi-lO-EOj" userLabel="First Responder" sceneMemberID="firstResponder"/>
  25.262              </objects>
  25.263 -            <point key="canvasLocation" x="-391" y="422"/>
  25.264 +            <point key="canvasLocation" x="-1327" y="442"/>
  25.265          </scene>
  25.266          <!--Trusted Server Settings View Controller-->
  25.267          <scene sceneID="ayN-a1-vAb">
  25.268 @@ -793,7 +813,7 @@
  25.269                          <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
  25.270                          <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
  25.271                          <prototypes>
  25.272 -                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="TrustedServerSettingCell" id="PoR-ac-chb" customClass="TrustedServerSettingCell" customModule="pEpForiOS" customModuleProvider="target">
  25.273 +                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" reuseIdentifier="TrustedServerSettingCell" id="PoR-ac-chb" customClass="TrustedServerSettingCell" customModule="pEpForiOS" customModuleProvider="target">
  25.274                                  <rect key="frame" x="0.0" y="55.5" width="375" height="43.5"/>
  25.275                                  <autoresizingMask key="autoresizingMask"/>
  25.276                                  <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="PoR-ac-chb" id="dSZ-uk-uWx">
  25.277 @@ -835,7 +855,7 @@
  25.278                  </tableViewController>
  25.279                  <placeholder placeholderIdentifier="IBFirstResponder" id="d7G-qu-RO5" userLabel="First Responder" sceneMemberID="firstResponder"/>
  25.280              </objects>
  25.281 -            <point key="canvasLocation" x="2276" y="-390.85457271364322"/>
  25.282 +            <point key="canvasLocation" x="510" y="-392"/>
  25.283          </scene>
  25.284          <!--Setting Default Account Table View Controller-->
  25.285          <scene sceneID="26G-EO-g0Z">
  25.286 @@ -872,7 +892,7 @@
  25.287                  </tableViewController>
  25.288                  <placeholder placeholderIdentifier="IBFirstResponder" id="a0D-hC-kA1" userLabel="First Responder" sceneMemberID="firstResponder"/>
  25.289              </objects>
  25.290 -            <point key="canvasLocation" x="1388" y="-389.05547226386807"/>
  25.291 +            <point key="canvasLocation" x="-388" y="-391"/>
  25.292          </scene>
  25.293          <!--Navigation Controller-->
  25.294          <scene sceneID="uMt-7B-UA8">
  25.295 @@ -890,7 +910,7 @@
  25.296                  </navigationController>
  25.297                  <placeholder placeholderIdentifier="IBFirstResponder" id="GlG-Ym-lHb" userLabel="First Responder" sceneMemberID="firstResponder"/>
  25.298              </objects>
  25.299 -            <point key="canvasLocation" x="-391.19999999999999" y="-388.15592203898052"/>
  25.300 +            <point key="canvasLocation" x="-1327" y="-389"/>
  25.301          </scene>
  25.302          <!--Editable Account Settings View Controller-->
  25.303          <scene sceneID="GDI-yq-B0C">
  25.304 @@ -934,7 +954,7 @@
  25.305                  </viewController>
  25.306                  <placeholder placeholderIdentifier="IBFirstResponder" id="VYD-1J-s8m" userLabel="First Responder" sceneMemberID="firstResponder"/>
  25.307              </objects>
  25.308 -            <point key="canvasLocation" x="343" y="425"/>
  25.309 +            <point key="canvasLocation" x="-388" y="441"/>
  25.310          </scene>
  25.311          <!--Editable Account Settings Table View Controller-->
  25.312          <scene sceneID="9s9-Il-XHa">
  25.313 @@ -1011,41 +1031,9 @@
  25.314                                              </constraints>
  25.315                                          </tableViewCellContentView>
  25.316                                      </tableViewCell>
  25.317 -                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="YqV-Wh-oH1">
  25.318 +                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="IIt-5z-bsQ">
  25.319                                          <rect key="frame" x="0.0" y="106" width="375" height="44"/>
  25.320                                          <autoresizingMask key="autoresizingMask"/>
  25.321 -                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="YqV-Wh-oH1" id="tIS-PS-HTE">
  25.322 -                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
  25.323 -                                            <autoresizingMask key="autoresizingMask"/>
  25.324 -                                            <subviews>
  25.325 -                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Username:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HRI-Z1-9IK">
  25.326 -                                                    <rect key="frame" x="20" y="11.5" width="84" height="21"/>
  25.327 -                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
  25.328 -                                                    <nil key="textColor"/>
  25.329 -                                                    <nil key="highlightedColor"/>
  25.330 -                                                </label>
  25.331 -                                                <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="YhU-oF-sEk">
  25.332 -                                                    <rect key="frame" x="112" y="5" width="243" height="34"/>
  25.333 -                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
  25.334 -                                                    <textInputTraits key="textInputTraits"/>
  25.335 -                                                    <connections>
  25.336 -                                                        <outlet property="delegate" destination="a1y-j3-omP" id="uuj-fr-YEz"/>
  25.337 -                                                    </connections>
  25.338 -                                                </textField>
  25.339 -                                            </subviews>
  25.340 -                                            <constraints>
  25.341 -                                                <constraint firstItem="YhU-oF-sEk" firstAttribute="top" secondItem="tIS-PS-HTE" secondAttribute="top" constant="5" id="48r-zC-qHz"/>
  25.342 -                                                <constraint firstAttribute="bottom" secondItem="YhU-oF-sEk" secondAttribute="bottom" constant="5" id="4O9-o7-5jD"/>
  25.343 -                                                <constraint firstAttribute="trailing" secondItem="YhU-oF-sEk" secondAttribute="trailing" constant="20" symbolic="YES" id="Cmx-tM-Bl1"/>
  25.344 -                                                <constraint firstItem="YhU-oF-sEk" firstAttribute="leading" secondItem="HRI-Z1-9IK" secondAttribute="trailing" constant="8" id="JuN-hA-lTB"/>
  25.345 -                                                <constraint firstItem="HRI-Z1-9IK" firstAttribute="centerY" secondItem="tIS-PS-HTE" secondAttribute="centerY" id="ZSa-Or-BaZ"/>
  25.346 -                                                <constraint firstItem="HRI-Z1-9IK" firstAttribute="leading" secondItem="tIS-PS-HTE" secondAttribute="leading" constant="20" symbolic="YES" id="ouo-Nj-Ah3"/>
  25.347 -                                            </constraints>
  25.348 -                                        </tableViewCellContentView>
  25.349 -                                    </tableViewCell>
  25.350 -                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="IIt-5z-bsQ">
  25.351 -                                        <rect key="frame" x="0.0" y="150" width="375" height="44"/>
  25.352 -                                        <autoresizingMask key="autoresizingMask"/>
  25.353                                          <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="IIt-5z-bsQ" id="uJQ-FX-wWp">
  25.354                                              <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
  25.355                                              <autoresizingMask key="autoresizingMask"/>
  25.356 @@ -1080,7 +1068,7 @@
  25.357                              <tableViewSection id="rVi-kC-gAd">
  25.358                                  <cells>
  25.359                                      <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="KeX-JE-Dde">
  25.360 -                                        <rect key="frame" x="0.0" y="230" width="375" height="44"/>
  25.361 +                                        <rect key="frame" x="0.0" y="186" width="375" height="44"/>
  25.362                                          <autoresizingMask key="autoresizingMask"/>
  25.363                                          <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KeX-JE-Dde" id="Qvm-Mg-c3O">
  25.364                                              <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
  25.365 @@ -1112,7 +1100,7 @@
  25.366                                          </tableViewCellContentView>
  25.367                                      </tableViewCell>
  25.368                                      <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="xZq-19-0BF">
  25.369 -                                        <rect key="frame" x="0.0" y="274" width="375" height="44"/>
  25.370 +                                        <rect key="frame" x="0.0" y="230" width="375" height="44"/>
  25.371                                          <autoresizingMask key="autoresizingMask"/>
  25.372                                          <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="xZq-19-0BF" id="SZP-9Z-P03">
  25.373                                              <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
  25.374 @@ -1144,7 +1132,7 @@
  25.375                                          </tableViewCellContentView>
  25.376                                      </tableViewCell>
  25.377                                      <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="Za8-Yq-EiZ">
  25.378 -                                        <rect key="frame" x="0.0" y="318" width="375" height="44"/>
  25.379 +                                        <rect key="frame" x="0.0" y="274" width="375" height="44"/>
  25.380                                          <autoresizingMask key="autoresizingMask"/>
  25.381                                          <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Za8-Yq-EiZ" id="Yrd-Pp-3Qf">
  25.382                                              <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
  25.383 @@ -1175,6 +1163,38 @@
  25.384                                              </constraints>
  25.385                                          </tableViewCellContentView>
  25.386                                      </tableViewCell>
  25.387 +                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="Pp2-jb-p0m">
  25.388 +                                        <rect key="frame" x="0.0" y="318" width="375" height="44"/>
  25.389 +                                        <autoresizingMask key="autoresizingMask"/>
  25.390 +                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Pp2-jb-p0m" id="H0E-jw-Ql1">
  25.391 +                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
  25.392 +                                            <autoresizingMask key="autoresizingMask"/>
  25.393 +                                            <subviews>
  25.394 +                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Username:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XM1-gc-evF">
  25.395 +                                                    <rect key="frame" x="20" y="11.5" width="84" height="21"/>
  25.396 +                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
  25.397 +                                                    <nil key="textColor"/>
  25.398 +                                                    <nil key="highlightedColor"/>
  25.399 +                                                </label>
  25.400 +                                                <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="zyk-Lc-i6M">
  25.401 +                                                    <rect key="frame" x="112" y="5" width="243" height="34"/>
  25.402 +                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
  25.403 +                                                    <textInputTraits key="textInputTraits"/>
  25.404 +                                                    <connections>
  25.405 +                                                        <outlet property="delegate" destination="a1y-j3-omP" id="zKy-O7-23U"/>
  25.406 +                                                    </connections>
  25.407 +                                                </textField>
  25.408 +                                            </subviews>
  25.409 +                                            <constraints>
  25.410 +                                                <constraint firstItem="zyk-Lc-i6M" firstAttribute="top" secondItem="H0E-jw-Ql1" secondAttribute="top" constant="5" id="9IN-2u-bVq"/>
  25.411 +                                                <constraint firstItem="XM1-gc-evF" firstAttribute="centerY" secondItem="H0E-jw-Ql1" secondAttribute="centerY" id="PoD-rw-KkX"/>
  25.412 +                                                <constraint firstItem="zyk-Lc-i6M" firstAttribute="leading" secondItem="XM1-gc-evF" secondAttribute="trailing" constant="8" id="cfj-B4-Yfe"/>
  25.413 +                                                <constraint firstItem="XM1-gc-evF" firstAttribute="leading" secondItem="H0E-jw-Ql1" secondAttribute="leading" constant="20" symbolic="YES" id="jvL-z2-4aF"/>
  25.414 +                                                <constraint firstAttribute="bottom" secondItem="zyk-Lc-i6M" secondAttribute="bottom" constant="5" id="mfA-FW-bpn"/>
  25.415 +                                                <constraint firstAttribute="trailing" secondItem="zyk-Lc-i6M" secondAttribute="trailing" constant="20" symbolic="YES" id="uhf-m0-hw5"/>
  25.416 +                                            </constraints>
  25.417 +                                        </tableViewCellContentView>
  25.418 +                                    </tableViewCell>
  25.419                                  </cells>
  25.420                              </tableViewSection>
  25.421                              <tableViewSection id="KKk-8Y-sdx">
  25.422 @@ -1275,6 +1295,38 @@
  25.423                                              </constraints>
  25.424                                          </tableViewCellContentView>
  25.425                                      </tableViewCell>
  25.426 +                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="JHi-0T-FoG">
  25.427 +                                        <rect key="frame" x="0.0" y="530" width="375" height="44"/>
  25.428 +                                        <autoresizingMask key="autoresizingMask"/>
  25.429 +                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="JHi-0T-FoG" id="VrV-X3-qNG">
  25.430 +                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
  25.431 +                                            <autoresizingMask key="autoresizingMask"/>
  25.432 +                                            <subviews>
  25.433 +                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Username:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jq7-2N-3eF">
  25.434 +                                                    <rect key="frame" x="20" y="11.5" width="84" height="21"/>
  25.435 +                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
  25.436 +                                                    <nil key="textColor"/>
  25.437 +                                                    <nil key="highlightedColor"/>
  25.438 +                                                </label>
  25.439 +                                                <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="nFy-FB-5mo">
  25.440 +                                                    <rect key="frame" x="112" y="5" width="243" height="34"/>
  25.441 +                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
  25.442 +                                                    <textInputTraits key="textInputTraits"/>
  25.443 +                                                    <connections>
  25.444 +                                                        <outlet property="delegate" destination="a1y-j3-omP" id="jL6-6Y-NRx"/>
  25.445 +                                                    </connections>
  25.446 +                                                </textField>
  25.447 +                                            </subviews>
  25.448 +                                            <constraints>
  25.449 +                                                <constraint firstItem="jq7-2N-3eF" firstAttribute="leading" secondItem="VrV-X3-qNG" secondAttribute="leading" constant="20" symbolic="YES" id="9yU-GS-qyn"/>
  25.450 +                                                <constraint firstAttribute="bottom" secondItem="nFy-FB-5mo" secondAttribute="bottom" constant="5" id="BWL-xH-jQz"/>
  25.451 +                                                <constraint firstAttribute="trailing" secondItem="nFy-FB-5mo" secondAttribute="trailing" constant="20" symbolic="YES" id="Y6e-U1-Y6m"/>
  25.452 +                                                <constraint firstItem="jq7-2N-3eF" firstAttribute="centerY" secondItem="VrV-X3-qNG" secondAttribute="centerY" id="ez5-sc-gow"/>
  25.453 +                                                <constraint firstItem="nFy-FB-5mo" firstAttribute="leading" secondItem="jq7-2N-3eF" secondAttribute="trailing" constant="8" id="fa3-xb-kd5"/>
  25.454 +                                                <constraint firstItem="nFy-FB-5mo" firstAttribute="top" secondItem="VrV-X3-qNG" secondAttribute="top" constant="5" id="sRF-yt-jTE"/>
  25.455 +                                            </constraints>
  25.456 +                                        </tableViewCellContentView>
  25.457 +                                    </tableViewCell>
  25.458                                  </cells>
  25.459                              </tableViewSection>
  25.460                          </sections>
  25.461 @@ -1291,6 +1343,7 @@
  25.462                          <outlet property="imapPortTextfield" destination="v1T-eA-l7v" id="Y6r-XD-Mqs"/>
  25.463                          <outlet property="imapSecurityTextfield" destination="j75-3B-i96" id="zmm-tS-qPj"/>
  25.464                          <outlet property="imapServerTextfield" destination="Hs1-fg-6Jo" id="MFb-h6-IuY"/>
  25.465 +                        <outlet property="imapUsernameTextfield" destination="zyk-Lc-i6M" id="u31-aG-EsD"/>
  25.466                          <outlet property="nameTextfield" destination="ff8-vj-4Ej" id="pcZ-iz-Cqc"/>
  25.467                          <outlet property="passwordTableViewCell" destination="IIt-5z-bsQ" id="QyA-zJ-HMv"/>
  25.468                          <outlet property="passwordTextfield" destination="uNX-Zg-59c" id="x30-HT-ODP"/>
  25.469 @@ -1298,7 +1351,7 @@
  25.470                          <outlet property="smtpPortTextfield" destination="85g-mE-AIj" id="SNo-2D-HfD"/>
  25.471                          <outlet property="smtpSecurityTextfield" destination="ftR-ql-mBD" id="hbR-KE-m8k"/>
  25.472                          <outlet property="smtpServerTextfield" destination="7YP-at-PfI" id="krD-pL-2Py"/>
  25.473 -                        <outlet property="usernameTextfield" destination="YhU-oF-sEk" id="jdH-ce-k67"/>
  25.474 +                        <outlet property="smtpUsernameTextfield" destination="nFy-FB-5mo" id="lzF-FX-3S4"/>
  25.475                      </connections>
  25.476                  </tableViewController>
  25.477                  <placeholder placeholderIdentifier="IBFirstResponder" id="gb9-RM-5S8" userLabel="First Responder" sceneMemberID="firstResponder"/>
  25.478 @@ -1314,7 +1367,68 @@
  25.479                      </connections>
  25.480                  </pickerView>
  25.481              </objects>
  25.482 -            <point key="canvasLocation" x="1186" y="480"/>
  25.483 +            <point key="canvasLocation" x="510" y="441"/>
  25.484 +        </scene>
  25.485 +        <!--Per Account Sync View Controller-->
  25.486 +        <scene sceneID="53l-6c-TqX">
  25.487 +            <objects>
  25.488 +                <viewController id="ubf-gx-0YH" customClass="PerAccountSyncViewController" customModule="pEpForiOS" customModuleProvider="target" sceneMemberID="viewController">
  25.489 +                    <view key="view" contentMode="scaleToFill" id="hhq-PL-Q5g">
  25.490 +                        <rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
  25.491 +                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
  25.492 +                        <subviews>
  25.493 +                            <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="nVh-uI-JiE">
  25.494 +                                <rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
  25.495 +                                <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
  25.496 +                                <prototypes>
  25.497 +                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="AccountCell" id="aEK-8s-TV6" customClass="PerAccountSyncAccountTableViewCell" customModule="pEpForiOS" customModuleProvider="target">
  25.498 +                                        <rect key="frame" x="0.0" y="28" width="375" height="43.5"/>
  25.499 +                                        <autoresizingMask key="autoresizingMask"/>
  25.500 +                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="aEK-8s-TV6" id="L50-hP-Nfh">
  25.501 +                                            <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
  25.502 +                                            <autoresizingMask key="autoresizingMask"/>
  25.503 +                                            <subviews>
  25.504 +                                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Jxa-Qh-LP1">
  25.505 +                                                    <rect key="frame" x="309" y="6.5" width="51" height="31"/>
  25.506 +                                                </switch>
  25.507 +                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="An3-RK-rIi">
  25.508 +                                                    <rect key="frame" x="15" y="11.5" width="42" height="21"/>
  25.509 +                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
  25.510 +                                                    <nil key="textColor"/>
  25.511 +                                                    <nil key="highlightedColor"/>
  25.512 +                                                </label>
  25.513 +                                            </subviews>
  25.514 +                                            <constraints>
  25.515 +                                                <constraint firstItem="An3-RK-rIi" firstAttribute="centerY" secondItem="L50-hP-Nfh" secondAttribute="centerY" id="9vO-Cf-uZ8"/>
  25.516 +                                                <constraint firstItem="Jxa-Qh-LP1" firstAttribute="centerY" secondItem="L50-hP-Nfh" secondAttribute="centerY" id="Mrr-yW-Ieq"/>
  25.517 +                                                <constraint firstItem="An3-RK-rIi" firstAttribute="leading" secondItem="L50-hP-Nfh" secondAttribute="leadingMargin" id="d1Q-EV-suC"/>
  25.518 +                                                <constraint firstAttribute="trailing" secondItem="Jxa-Qh-LP1" secondAttribute="trailing" constant="17" id="gsw-Lb-Wij"/>
  25.519 +                                            </constraints>
  25.520 +                                        </tableViewCellContentView>
  25.521 +                                        <connections>
  25.522 +                                            <outlet property="accountTitleLabel" destination="An3-RK-rIi" id="WPa-ce-6CT"/>
  25.523 +                                            <outlet property="perAccountSwitch" destination="Jxa-Qh-LP1" id="TW3-ao-n0b"/>
  25.524 +                                        </connections>
  25.525 +                                    </tableViewCell>
  25.526 +                                </prototypes>
  25.527 +                            </tableView>
  25.528 +                        </subviews>
  25.529 +                        <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
  25.530 +                        <constraints>
  25.531 +                            <constraint firstItem="nVh-uI-JiE" firstAttribute="leading" secondItem="E4R-XF-wwh" secondAttribute="leading" id="906-IE-Zr3"/>
  25.532 +                            <constraint firstItem="E4R-XF-wwh" firstAttribute="trailing" secondItem="nVh-uI-JiE" secondAttribute="trailing" id="XzB-ZP-mpw"/>
  25.533 +                            <constraint firstItem="E4R-XF-wwh" firstAttribute="bottom" secondItem="nVh-uI-JiE" secondAttribute="bottom" id="YGX-Vs-cow"/>
  25.534 +                            <constraint firstItem="nVh-uI-JiE" firstAttribute="top" secondItem="E4R-XF-wwh" secondAttribute="top" id="nk7-VH-kCK"/>
  25.535 +                        </constraints>
  25.536 +                        <viewLayoutGuide key="safeArea" id="E4R-XF-wwh"/>
  25.537 +                    </view>
  25.538 +                    <connections>
  25.539 +                        <outlet property="tableView" destination="nVh-uI-JiE" id="SFZ-9v-cMd"/>
  25.540 +                    </connections>
  25.541 +                </viewController>
  25.542 +                <placeholder placeholderIdentifier="IBFirstResponder" id="C8G-kv-oTS" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
  25.543 +            </objects>
  25.544 +            <point key="canvasLocation" x="-1305" y="-1952"/>
  25.545          </scene>
  25.546      </scenes>
  25.547  </document>
    26.1 --- a/pEpForiOS/Base.lproj/Thread.storyboard	Fri Feb 07 12:29:26 2020 +0100
    26.2 +++ b/pEpForiOS/Base.lproj/Thread.storyboard	Fri Feb 07 12:31:01 2020 +0100
    26.3 @@ -1,21 +1,17 @@
    26.4  <?xml version="1.0" encoding="UTF-8"?>
    26.5 -<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="03X-Fp-JsF">
    26.6 -    <device id="retina4_7" orientation="portrait">
    26.7 -        <adaptation id="fullscreen"/>
    26.8 -    </device>
    26.9 +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="03X-Fp-JsF">
   26.10 +    <device id="retina4_7" orientation="portrait" appearance="light"/>
   26.11      <dependencies>
   26.12          <deployment identifier="iOS"/>
   26.13 -        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
   26.14 -        <capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
   26.15 -        <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
   26.16 +        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15510"/>
   26.17          <capability name="Safe area layout guides" minToolsVersion="9.0"/>
   26.18          <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
   26.19      </dependencies>
   26.20      <scenes>
   26.21 -        <!--emailDetail-->
   26.22 +        <!--EmailViewController-->
   26.23          <scene sceneID="fOY-zG-WpI">
   26.24              <objects>
   26.25 -                <viewControllerPlaceholder storyboardName="Main" referencedIdentifier="emailDetail" id="Kkk-c0-S5g" sceneMemberID="viewController"/>
   26.26 +                <viewControllerPlaceholder storyboardName="Main" referencedIdentifier="EmailViewController" id="Kkk-c0-S5g" sceneMemberID="viewController"/>
   26.27                  <placeholder placeholderIdentifier="IBFirstResponder" id="RVi-sQ-VYD" userLabel="First Responder" sceneMemberID="firstResponder"/>
   26.28              </objects>
   26.29              <point key="canvasLocation" x="8734" y="-488"/>
   26.30 @@ -25,11 +21,11 @@
   26.31              <objects>
   26.32                  <viewController storyboardIdentifier="threadViewController" id="8tS-ie-Ovo" customClass="ThreadViewController" customModule="pEpForiOS" customModuleProvider="target" sceneMemberID="viewController">
   26.33                      <view key="view" contentMode="scaleToFill" id="li9-eb-DlS">
   26.34 -                        <rect key="frame" x="0.0" y="0.0" width="375" height="603"/>
   26.35 +                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
   26.36                          <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
   26.37                          <subviews>
   26.38                              <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="none" rowHeight="-1" estimatedRowHeight="300" sectionHeaderHeight="6" sectionFooterHeight="6" translatesAutoresizingMaskIntoConstraints="NO" id="Yrb-DL-w8R">
   26.39 -                                <rect key="frame" x="0.0" y="0.0" width="375" height="559"/>
   26.40 +                                <rect key="frame" x="0.0" y="0.0" width="375" height="574"/>
   26.41                                  <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
   26.42                                  <prototypes>
   26.43                                      <tableViewCell opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="unexpandedCell" rowHeight="100" id="i6i-Xi-PQA" customClass="EmailListViewCell" customModule="pEpForiOS" customModuleProvider="target">
   26.44 @@ -49,7 +45,7 @@
   26.45                                                              <nil key="highlightedColor"/>
   26.46                                                          </label>
   26.47                                                          <label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalCompressionResistancePriority="1000" text="Summary" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tKI-X2-ryx">
   26.48 -                                                            <rect key="frame" x="72" y="58" width="265" height="20.5"/>
   26.49 +                                                            <rect key="frame" x="72" y="58.5" width="265" height="20.5"/>
   26.50                                                              <fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
   26.51                                                              <color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="calibratedWhite"/>
   26.52                                                              <nil key="highlightedColor"/>
   26.53 @@ -467,7 +463,7 @@
   26.54                      <toolbarItems/>
   26.55                      <simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
   26.56                      <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="49e-ck-OVT">
   26.57 -                        <rect key="frame" x="0.0" y="20" width="375" height="44"/>
   26.58 +                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
   26.59                          <autoresizingMask key="autoresizingMask"/>
   26.60                      </navigationBar>
   26.61                      <nil name="viewControllers"/>
    27.1 --- a/pEpForiOS/KeySync/KeySyncDeviceGroupUtil.swift	Fri Feb 07 12:29:26 2020 +0100
    27.2 +++ b/pEpForiOS/KeySync/KeySyncDeviceGroupUtil.swift	Fri Feb 07 12:31:01 2020 +0100
    27.3 @@ -10,23 +10,24 @@
    27.4  import PEPObjCAdapterFramework
    27.5  
    27.6  protocol KeySyncUtilProtocol: class {
    27.7 -    static var deviceGroupState: DeviceGroupState { get }
    27.8      static func leaveDeviceGroup() throws
    27.9      static var isInDeviceGroup: Bool { get }
   27.10      static var isKeySyncEnabled: Bool { get }
   27.11      static func enableKeySync()
   27.12      static func disableKeySync()
   27.13 -
   27.14  }
   27.15  
   27.16 -class KeySyncUtil: KeySyncUtilProtocol {
   27.17 +class KeySyncUtil {
   27.18  
   27.19      /// Pure static API.
   27.20      private init() {}
   27.21  
   27.22 -    static var deviceGroupState: DeviceGroupState {
   27.23 +    static private var deviceGroupState: DeviceGroupState {
   27.24          return AppSettings.shared.lastKnownDeviceGroupState
   27.25      }
   27.26 +}
   27.27 +
   27.28 +extension KeySyncUtil: KeySyncUtilProtocol {
   27.29  
   27.30      static func leaveDeviceGroup() throws {
   27.31          try PEPSession().leaveDeviceGroup()
   27.32 @@ -47,6 +48,13 @@
   27.33      }
   27.34  
   27.35      static func disableKeySync() {
   27.36 +        if isInDeviceGroup {
   27.37 +            do {
   27.38 +                try leaveDeviceGroup()
   27.39 +            } catch {
   27.40 +                Log.shared.errorAndCrash(error: error)
   27.41 +            }
   27.42 +        }
   27.43          AppSettings.shared.keySyncEnabled = false
   27.44      }
   27.45  }
    28.1 --- a/pEpForiOS/Models/FolderType+Extensions.swift	Fri Feb 07 12:29:26 2020 +0100
    28.2 +++ b/pEpForiOS/Models/FolderType+Extensions.swift	Fri Feb 07 12:31:01 2020 +0100
    28.3 @@ -18,7 +18,7 @@
    28.4      func getIcon() -> UIImage {
    28.5          var imageName: String?
    28.6          switch self {
    28.7 -        case .normal:
    28.8 +        case .normal, .pEpSync:
    28.9              imageName = "folders-icon-folder"
   28.10          case .archive:
   28.11              imageName = "folders-icon-archive"
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/pEpForiOS/Resources/Assets.xcassets/NavigationBar/close-icon.imageset/Contents.json	Fri Feb 07 12:31:01 2020 +0100
    29.3 @@ -0,0 +1,16 @@
    29.4 +{
    29.5 +  "images" : [
    29.6 +    {
    29.7 +      "idiom" : "universal",
    29.8 +      "filename" : "close-icon.pdf"
    29.9 +    }
   29.10 +  ],
   29.11 +  "info" : {
   29.12 +    "version" : 1,
   29.13 +    "author" : "xcode"
   29.14 +  },
   29.15 +  "properties" : {
   29.16 +    "template-rendering-intent" : "original",
   29.17 +    "preserves-vector-representation" : true
   29.18 +  }
   29.19 +}
   29.20 \ No newline at end of file
    30.1 Binary file pEpForiOS/Resources/Assets.xcassets/NavigationBar/close-icon.imageset/close-icon.pdf has changed
    31.1 --- a/pEpForiOS/Resources/Assets.xcassets/icon-settings.imageset/Contents.json	Fri Feb 07 12:29:26 2020 +0100
    31.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.3 @@ -1,21 +0,0 @@
    31.4 -{
    31.5 -  "images" : [
    31.6 -    {
    31.7 -      "idiom" : "universal",
    31.8 -      "filename" : "pEpForiOS-icon-settings.pdf",
    31.9 -      "scale" : "1x"
   31.10 -    },
   31.11 -    {
   31.12 -      "idiom" : "universal",
   31.13 -      "scale" : "2x"
   31.14 -    },
   31.15 -    {
   31.16 -      "idiom" : "universal",
   31.17 -      "scale" : "3x"
   31.18 -    }
   31.19 -  ],
   31.20 -  "info" : {
   31.21 -    "version" : 1,
   31.22 -    "author" : "xcode"
   31.23 -  }
   31.24 -}
   31.25 \ No newline at end of file
    32.1 Binary file pEpForiOS/Resources/Assets.xcassets/icon-settings.imageset/pEpForiOS-icon-settings.pdf has changed
    33.1 Binary file pEpForiOS/Resources/Assets.xcassets/pEp Status/pEp-status-green-disabled.imageset/pEp-status-green-disabled.pdf has changed
    34.1 Binary file pEpForiOS/Resources/Assets.xcassets/pEp Status/pEp-status-green-disabled.imageset/pep-status-green-disabled.pdf has changed
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/pEpForiOS/Resources/Assets.xcassets/pEp-Icon/Contents.json	Fri Feb 07 12:31:01 2020 +0100
    35.3 @@ -0,0 +1,6 @@
    35.4 +{
    35.5 +  "info" : {
    35.6 +    "version" : 1,
    35.7 +    "author" : "xcode"
    35.8 +  }
    35.9 +}
   35.10 \ No newline at end of file
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/pEpForiOS/Resources/Assets.xcassets/pEp-Icon/icon-settings.imageset/Contents.json	Fri Feb 07 12:31:01 2020 +0100
    36.3 @@ -0,0 +1,21 @@
    36.4 +{
    36.5 +  "images" : [
    36.6 +    {
    36.7 +      "idiom" : "universal",
    36.8 +      "filename" : "pEpForiOS-icon-settings.pdf",
    36.9 +      "scale" : "1x"
   36.10 +    },
   36.11 +    {
   36.12 +      "idiom" : "universal",
   36.13 +      "scale" : "2x"
   36.14 +    },
   36.15 +    {
   36.16 +      "idiom" : "universal",
   36.17 +      "scale" : "3x"
   36.18 +    }
   36.19 +  ],
   36.20 +  "info" : {
   36.21 +    "version" : 1,
   36.22 +    "author" : "xcode"
   36.23 +  }
   36.24 +}
   36.25 \ No newline at end of file
    37.1 Binary file pEpForiOS/Resources/Assets.xcassets/pEp-Icon/icon-settings.imageset/pEpForiOS-icon-settings.pdf has changed
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/pEpForiOS/Resources/Assets.xcassets/pEp-Icon/icon-unsecure-top.imageset/Contents.json	Fri Feb 07 12:31:01 2020 +0100
    38.3 @@ -0,0 +1,21 @@
    38.4 +{
    38.5 +  "images" : [
    38.6 +    {
    38.7 +      "idiom" : "universal",
    38.8 +      "filename" : "pEpForiOS-icon-unsecure-top.pdf",
    38.9 +      "scale" : "1x"
   38.10 +    },
   38.11 +    {
   38.12 +      "idiom" : "universal",
   38.13 +      "scale" : "2x"
   38.14 +    },
   38.15 +    {
   38.16 +      "idiom" : "universal",
   38.17 +      "scale" : "3x"
   38.18 +    }
   38.19 +  ],
   38.20 +  "info" : {
   38.21 +    "version" : 1,
   38.22 +    "author" : "xcode"
   38.23 +  }
   38.24 +}
   38.25 \ No newline at end of file
    39.1 Binary file pEpForiOS/Resources/Assets.xcassets/pEp-Icon/icon-unsecure-top.imageset/pEpForiOS-icon-unsecure-top.pdf has changed
    40.1 --- a/pEpForiOS/Resources/Assets.xcassets/pep-logo.imageset/Contents.json	Fri Feb 07 12:29:26 2020 +0100
    40.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.3 @@ -1,12 +0,0 @@
    40.4 -{
    40.5 -  "images" : [
    40.6 -    {
    40.7 -      "idiom" : "universal",
    40.8 -      "filename" : "pEp-logo.pdf"
    40.9 -    }
   40.10 -  ],
   40.11 -  "info" : {
   40.12 -    "version" : 1,
   40.13 -    "author" : "xcode"
   40.14 -  }
   40.15 -}
    41.1 Binary file pEpForiOS/Resources/Assets.xcassets/pep-logo.imageset/pEp-logo.pdf has changed
    42.1 --- a/pEpForiOS/UI/BaseClasses/BaseViewController.swift	Fri Feb 07 12:29:26 2020 +0100
    42.2 +++ b/pEpForiOS/UI/BaseClasses/BaseViewController.swift	Fri Feb 07 12:31:01 2020 +0100
    42.3 @@ -102,3 +102,47 @@
    42.4          }
    42.5      }
    42.6  }
    42.7 +
    42.8 +// MARK: - Stuff copy & pasted from BaseTableViewController.
    42.9 +
   42.10 +extension BaseViewController {
   42.11 +
   42.12 +    /// If applicable, shows the "empty selection" view controller in the details view.
   42.13 +    /// - Parameter message: The message to show in the view.
   42.14 +    func showEmptyDetailViewIfApplicable(message: String) {
   42.15 +        guard let spvc = splitViewController else {
   42.16 +            return
   42.17 +        }
   42.18 +
   42.19 +        /// Inner function for doing the actual work.
   42.20 +        func showEmptyDetail() {
   42.21 +            let detailIndex = 1 // The index of the detail view controller
   42.22 +
   42.23 +            if let emptyVC = spvc.viewControllers[safe: detailIndex] as? NothingSelectedViewController {
   42.24 +                emptyVC.message = message
   42.25 +                emptyVC.updateView()
   42.26 +            } else {
   42.27 +                let storyboard: UIStoryboard = UIStoryboard(
   42.28 +                    name: UIStoryboard.noSelectionStoryBoard,
   42.29 +                    bundle: nil)
   42.30 +                guard let detailVC = storyboard.instantiateViewController(
   42.31 +                    withIdentifier: UIStoryboard.nothingSelectedViewController) as? NothingSelectedViewController else {
   42.32 +                        return
   42.33 +                }
   42.34 +                detailVC.message = message
   42.35 +                spvc.showDetailViewController(detailVC, sender: self)
   42.36 +            }
   42.37 +        }
   42.38 +
   42.39 +        switch spvc.currentDisplayMode {
   42.40 +        case .masterAndDetail:
   42.41 +            showEmptyDetail()
   42.42 +        case .onlyDetail:
   42.43 +            // nothing to do
   42.44 +            break
   42.45 +        case .onlyMaster:
   42.46 +            // nothing to do
   42.47 +            break
   42.48 +        }
   42.49 +    }
   42.50 +}
    43.1 --- a/pEpForiOS/UI/BaseClasses/PEPPageViewControllerBase.swift	Fri Feb 07 12:29:26 2020 +0100
    43.2 +++ b/pEpForiOS/UI/BaseClasses/PEPPageViewControllerBase.swift	Fri Feb 07 12:31:01 2020 +0100
    43.3 @@ -17,29 +17,38 @@
    43.4      var pageControlTint: UIColor?
    43.5      var showDots = false
    43.6      var isScrollEnable = false
    43.7 -    var didLoadValues = false
    43.8 +    /// Stuff to do exactly once in viewWillAppear
    43.9 +    private var doOnce: (()->())?
   43.10  
   43.11      var views = [UIViewController]()
   43.12  
   43.13      override func viewDidLoad() {
   43.14          super.viewDidLoad()
   43.15          delegate = self
   43.16 +        doOnce = { [weak self] in
   43.17 +            guard let me = self else {
   43.18 +                Log.shared.errorAndCrash("Lost myself")
   43.19 +                return
   43.20 +            }
   43.21 +            me.dataSource = me.showDots ? self : nil //nil dataSource will hide dots and disable scrolling
   43.22 +            if !me.isScrollEnable {
   43.23 +                me.disableScrolling()
   43.24 +            }
   43.25 +            if let firstView = me.views.first { //!!!: //BUFF: is views.first == nil a valid case?
   43.26 +                me.setViewControllers([firstView],
   43.27 +                                      direction: .forward,
   43.28 +                                      animated: true,
   43.29 +                                      completion: nil)
   43.30 +            }
   43.31 +            me.doOnce = nil
   43.32 +        }
   43.33      }
   43.34  
   43.35      override func viewWillAppear(_ animated: Bool) {
   43.36          super.viewWillAppear(animated)
   43.37  
   43.38          navigationController?.isToolbarHidden = false
   43.39 -        if !didLoadValues { //!!!: //BUFF: ugly.
   43.40 -            didLoadValues = true
   43.41 -            dataSource = showDots ? self : nil //nil dataSource will hide dots and disable scrolling
   43.42 -            if !isScrollEnable {
   43.43 -                disableScrolling()
   43.44 -            }
   43.45 -            if let firstView = views.first { //!!!: //BUFF: is views.first == nil a valid cas?
   43.46 -                setViewControllers([firstView], direction: .forward, animated: true, completion: nil)
   43.47 -            }
   43.48 -        }
   43.49 +        doOnce?()
   43.50      }
   43.51  
   43.52      override func viewDidLayoutSubviews() {
    44.1 --- a/pEpForiOS/UI/Compose/ComposeTableViewController.swift	Fri Feb 07 12:29:26 2020 +0100
    44.2 +++ b/pEpForiOS/UI/Compose/ComposeTableViewController.swift	Fri Feb 07 12:31:01 2020 +0100
    44.3 @@ -115,76 +115,63 @@
    44.4              Log.shared.errorAndCrash("No VM")
    44.5              return
    44.6          }
    44.7 +
    44.8          //Not so nice. The view(controller) should not know about state and protection.
    44.9          var view = showNavigationBarSecurityBadge(pEpRating: pEpRating, pEpProtection: pEpProtected)
   44.10 +
   44.11 +        // Show the logo instead if there is no pEp color
   44.12 +        if view == nil {
   44.13 +            view = showNavigationBarPEPLogo(pEpRating: pEpRating)
   44.14 +        }
   44.15 +
   44.16 +        // Handshake on simple touch if possible
   44.17          if vm.canDoHandshake() {
   44.18 -            if view == nil {
   44.19 -                view = showNavigationBarPEPLogo(pEpRating: pEpRating)
   44.20 -            }
   44.21 -            let tapGestureRecognizer = UITapGestureRecognizer(
   44.22 +            let tapGestureRecognizerHandshake = UITapGestureRecognizer(
   44.23                  target: self,
   44.24 -                action: #selector(actionHandshakeOrForceUnprotected))
   44.25 -            view?.addGestureRecognizer(tapGestureRecognizer)
   44.26 +                action: #selector(actionHandshake))
   44.27 +            view?.addGestureRecognizer(tapGestureRecognizerHandshake)
   44.28 +        }
   44.29 +
   44.30 +        // Toggle privacy status on long press for trusted and reliable
   44.31 +        let pEpColor = pEpRating.pEpColor()
   44.32 +        if pEpColor == .green || pEpColor == .yellow {
   44.33 +            let tapGestureRecognizerToggleProtection = UILongPressGestureRecognizer(
   44.34 +                target: self,
   44.35 +                action: #selector(actionToggleProtection))
   44.36 +            view?.addGestureRecognizer(tapGestureRecognizerToggleProtection)
   44.37          }
   44.38      }
   44.39  
   44.40 -    /// Shows a menu where user can choose to make a handshake, or toggle force unprotected.
   44.41 -    @objc func actionHandshakeOrForceUnprotected(gestureRecognizer: UITapGestureRecognizer) {
   44.42 +    /// Toggles the protection for this outgoing message (force protected).
   44.43 +    /// - Parameter gestureRecognizer: The gesture recognizer that triggered this
   44.44 +    @objc func actionToggleProtection(gestureRecognizer: UITapGestureRecognizer) {
   44.45 +        // This is a long press, so react once when we know for sure,
   44.46 +        // while the user is still pressing.
   44.47 +        guard gestureRecognizer.state == .began else {
   44.48 +            return
   44.49 +        }
   44.50 +
   44.51          guard let vm = viewModel else {
   44.52              Log.shared.errorAndCrash("No VM")
   44.53              return
   44.54          }
   44.55 -        let theCanHandshake = vm.state.canHandshake()
   44.56 -        let theCanToggleProtection = vm.state.userCanToggleProtection()
   44.57 +        guard vm.state.userCanToggleProtection() else {
   44.58 +            return
   44.59 +        }
   44.60  
   44.61 -        if theCanHandshake || theCanToggleProtection {
   44.62 -            let alert = UIAlertController.pEpAlertController()
   44.63 +        let originalValueOfProtection = vm.state.pEpProtection
   44.64 +        vm.handleUserChangedProtectionStatus(to: !originalValueOfProtection)
   44.65 +    }
   44.66  
   44.67 -            if theCanHandshake {
   44.68 -                let actionReply = UIAlertAction(
   44.69 -                    title: NSLocalizedString("Handshake",
   44.70 -                                             comment: "possible privacy status action"),
   44.71 -                    style: .default) {[weak self] (action) in
   44.72 -                        self?.performSegue(withIdentifier: .segueHandshake, sender: self)
   44.73 -                }
   44.74 -                alert.addAction(actionReply)
   44.75 -            }
   44.76 -
   44.77 -            let tutorialAction = UIAlertAction(
   44.78 -                title: NSLocalizedString("Tutorial", comment: "show tutorial from compose view"),
   44.79 -                style: .default) { _ in
   44.80 -                    TutorialWizardViewController.presentTutorialWizard(viewController: self)
   44.81 -            }
   44.82 -            alert.addAction(tutorialAction)
   44.83 -
   44.84 -            if theCanToggleProtection {
   44.85 -                let originalValueOfProtection = vm.state.pEpProtection
   44.86 -                let title = vm.state.pEpProtection ?
   44.87 -                    NSLocalizedString("Disable Protection",
   44.88 -                                      comment: "possible private status action") :
   44.89 -                    NSLocalizedString("Enable Protection",
   44.90 -                                      comment: "possible private status action")
   44.91 -                let actionToggleProtection = UIAlertAction(
   44.92 -                    title: title,
   44.93 -                    style: .default) { (action) in
   44.94 -                        vm.handleUserChangedProtectionStatus(to: !originalValueOfProtection)
   44.95 -                }
   44.96 -                alert.addAction(actionToggleProtection)
   44.97 -            }
   44.98 -
   44.99 -            let cancelAction = UIAlertAction(
  44.100 -                title: NSLocalizedString("Cancel", comment: "possible private status action"),
  44.101 -                style: .cancel) { (action) in }
  44.102 -            alert.addAction(cancelAction)
  44.103 -            if let sourceView = gestureRecognizer.view {
  44.104 -                alert.popoverPresentationController?.sourceView = sourceView
  44.105 -                alert.popoverPresentationController?.sourceRect = CGRect(x: sourceView.bounds.midX,
  44.106 -                                                                         y: sourceView.bounds.maxY,
  44.107 -                                                                         width: 0,
  44.108 -                                                                         height: 0)
  44.109 -            }
  44.110 -
  44.111 -            present(alert, animated: true, completion: nil)
  44.112 +    /// Shows the handshake menu, if applicable.
  44.113 +    /// - Parameter gestureRecognizer: The gesture recognizer that triggered this
  44.114 +    @objc func actionHandshake(gestureRecognizer: UITapGestureRecognizer) {
  44.115 +        guard let vm = viewModel else {
  44.116 +            Log.shared.errorAndCrash("No VM")
  44.117 +            return
  44.118 +        }
  44.119 +        if (vm.state.canHandshake()) {
  44.120 +            self.performSegue(withIdentifier: .segueHandshake, sender: self)
  44.121          }
  44.122      }
  44.123  }
  44.124 @@ -608,7 +595,6 @@
  44.125                  Log.shared.errorAndCrash("Lost MySelf")
  44.126                  return
  44.127              }
  44.128 -            vm.handleDeleteActionTriggered()
  44.129              me.dismiss()
  44.130          }
  44.131          return action
    45.1 --- a/pEpForiOS/UI/Compose/ViewModel/ComposeViewModel+InitData.swift	Fri Feb 07 12:29:26 2020 +0100
    45.2 +++ b/pEpForiOS/UI/Compose/ViewModel/ComposeViewModel+InitData.swift	Fri Feb 07 12:31:01 2020 +0100
    45.3 @@ -40,11 +40,6 @@
    45.4  
    45.5          public let composeMode: ComposeUtil.ComposeMode
    45.6  
    45.7 -        /// Whether or not the original message is in Drafts or Outbox
    45.8 -        var isDraftsOrOutbox: Bool {
    45.9 -            return isDrafts || isOutbox
   45.10 -        }
   45.11 -
   45.12          /// Whether or not the original message is in Drafts folder
   45.13          var isDrafts: Bool {
   45.14              if let om = originalMessage {
   45.15 @@ -137,7 +132,7 @@
   45.16              case .forward:
   45.17                  subject = ReplyUtil.forwardSubject(message: originalMessage)
   45.18              case .normal:
   45.19 -                if isDraftsOrOutbox {
   45.20 +                if isDrafts {
   45.21                      subject = originalMessage.shortMessage ?? " "
   45.22                  }
   45.23                  // .normal is intentionally ignored here for other folder types
   45.24 @@ -157,7 +152,7 @@
   45.25              case .forward:
   45.26                  setBodyPotetionallyTakingOverAttachments()
   45.27              case .normal:
   45.28 -                if isDraftsOrOutbox {
   45.29 +                if isDrafts {
   45.30                      setBodyPotetionallyTakingOverAttachments()
   45.31                  }
   45.32                  // do nothing.
   45.33 @@ -176,14 +171,14 @@
   45.34              bodyHtml = text
   45.35          }
   45.36  
   45.37 -        /// Is sutable for isDraftsOrOutbox || composeMode == .forward only.
   45.38 +        /// Is sutable for isDrafts || composeMode == .forward only.
   45.39          mutating private func setBodyPotetionallyTakingOverAttachments() {
   45.40              guard let msg = originalMessage else {
   45.41                  Log.shared.errorAndCrash("Inconsitant state")
   45.42                  return
   45.43              }
   45.44  
   45.45 -            guard isDraftsOrOutbox || composeMode == .forward else {
   45.46 +            guard isDrafts || composeMode == .forward else {
   45.47                  Log.shared.errorAndCrash("Unsupported mode or message")
   45.48                  return
   45.49              }
    46.1 --- a/pEpForiOS/UI/Compose/ViewModel/ComposeViewModel.swift	Fri Feb 07 12:29:26 2020 +0100
    46.2 +++ b/pEpForiOS/UI/Compose/ViewModel/ComposeViewModel.swift	Fri Feb 07 12:31:01 2020 +0100
    46.3 @@ -10,18 +10,6 @@
    46.4  import pEpIOSToolbox
    46.5  import PEPObjCAdapterFramework
    46.6  
    46.7 -/// Informs the one that triggered the segued to here.
    46.8 -protocol ComposeViewModelResultDelegate: class {
    46.9 -    /// Called after a valid mail has been composed and saved for sending.
   46.10 -    func composeViewModelDidComposeNewMail(message: Message)
   46.11 -    /// Called after saving a modified version of the original message.
   46.12 -    /// (E.g. after editing a drafted message)
   46.13 -    func composeViewModelDidModifyMessage(message: Message)
   46.14 -    /// Called after permanentaly deleting the original message.
   46.15 -    /// (E.g. saving an edited oubox mail to drafts. It's permanentaly deleted from outbox.)
   46.16 -    func composeViewModelDidDeleteMessage(message: Message)
   46.17 -}
   46.18 -
   46.19  protocol ComposeViewModelDelegate: class {
   46.20  
   46.21      /// Called when the user changes the content of a row.
   46.22 @@ -60,7 +48,6 @@
   46.23  }
   46.24  
   46.25  class ComposeViewModel {
   46.26 -    weak var resultDelegate: ComposeViewModelResultDelegate?
   46.27      weak var delegate: ComposeViewModelDelegate? {
   46.28          didSet {
   46.29              delegate?.colorBatchNeedsUpdate(for: state.rating,
   46.30 @@ -88,12 +75,10 @@
   46.31      /// would thus crash if anone commits the main session.
   46.32      private let session = Session()
   46.33  
   46.34 -    init(resultDelegate: ComposeViewModelResultDelegate? = nil,
   46.35 -         composeMode: ComposeUtil.ComposeMode? = nil,
   46.36 +    init(composeMode: ComposeUtil.ComposeMode? = nil,
   46.37           prefilledTo: Identity? = nil,
   46.38           prefilledFrom: Identity? = nil,
   46.39           originalMessage: Message? = nil) {
   46.40 -        self.resultDelegate = resultDelegate
   46.41          let initData = InitData(withPrefilledToRecipient: prefilledTo,
   46.42                                  prefilledFromSender: prefilledFrom,
   46.43                                  orForOriginalMessage: originalMessage,
   46.44 @@ -149,13 +134,12 @@
   46.45              Log.shared.errorAndCrash("No data")
   46.46              return
   46.47          }
   46.48 -        if data.isDraftsOrOutbox {
   46.49 +        if data.isDrafts {
   46.50              // From user perspective, we have edited a drafted message and will send it.
   46.51              // Technically we are creating and sending a new message (msg), thus we have to
   46.52              // delete the original, previously drafted one.
   46.53              deleteOriginalMessage()
   46.54          }
   46.55 -        resultDelegate?.composeViewModelDidComposeNewMail(message: msg)
   46.56      }
   46.57  
   46.58      public func isAttachmentSection(indexPath: IndexPath) -> Bool {
   46.59 @@ -184,7 +168,6 @@
   46.60          // mailboxes, that show all flagged messages.
   46.61          om.imapFlags.draft = false
   46.62          om.imapMarkDeleted()
   46.63 -        resultDelegate?.composeViewModelDidDeleteMessage(message: om)
   46.64      }
   46.65  
   46.66      private func setup() {
   46.67 @@ -554,38 +537,16 @@
   46.68          return NSLocalizedString("Cancel", comment: "compose email cancel")
   46.69      }
   46.70  
   46.71 -    public func handleDeleteActionTriggered() {
   46.72 -        guard let data = state.initData else {
   46.73 -            Log.shared.errorAndCrash("No data")
   46.74 -            return
   46.75 -        }
   46.76 -
   46.77 -        if data.isOutbox {
   46.78 -            data.originalMessage?.delete()
   46.79 -            if let message = data.originalMessage {
   46.80 -                resultDelegate?.composeViewModelDidDeleteMessage(message: message)
   46.81 -            }
   46.82 -        }
   46.83 -    }
   46.84 -
   46.85      public func handleSaveActionTriggered() {
   46.86          guard let data = state.initData else {
   46.87              Log.shared.errorAndCrash("No data")
   46.88              return
   46.89          }
   46.90 -        if data.isDraftsOrOutbox {
   46.91 +        if data.isDrafts {
   46.92              // We are in drafts folder and, from user perespective, are editing a drafted mail.
   46.93              // Technically we have to create a new one and delete the original message, as the
   46.94 -            // mail is already synced with the IMAP server and thus we must not modify it.
   46.95 +            // mail is already synced with the IMAP server and thus we must/can not modify it.
   46.96              deleteOriginalMessage()
   46.97 -
   46.98 -            if data.isOutbox {
   46.99 -                // Message will be saved (moved from user perspective) to drafts, but we are in
  46.100 -                // outbox folder.
  46.101 -                if let message = data.originalMessage {
  46.102 -                    resultDelegate?.composeViewModelDidDeleteMessage(message: message)
  46.103 -                }
  46.104 -            }
  46.105          }
  46.106  
  46.107          guard let msg = ComposeUtil.messageToSend(withDataFrom: state) else {
  46.108 @@ -601,13 +562,6 @@
  46.109          msg.imapFlags.draft = true
  46.110          msg.sent = Date()
  46.111          Message.saveForAppend(msg: msg)
  46.112 -        if data.isDrafts {
  46.113 -            // We save a modified version of a drafted message. The UI might want to updtate
  46.114 -            // its model.
  46.115 -            if let message = data.originalMessage {
  46.116 -                resultDelegate?.composeViewModelDidModifyMessage(message: message)
  46.117 -            }
  46.118 -        }
  46.119      }
  46.120  }
  46.121  
  46.122 @@ -631,7 +585,7 @@
  46.123      }
  46.124  
  46.125      func canDoHandshake() -> Bool {
  46.126 -        return state.canHandshake() || state.userCanToggleProtection()
  46.127 +        return state.canHandshake()
  46.128      }
  46.129  }
  46.130  
    47.1 --- a/pEpForiOS/UI/EmailDisplay/Background/AttachmentToLocalURLOperation.swift	Fri Feb 07 12:29:26 2020 +0100
    47.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    47.3 @@ -1,52 +0,0 @@
    47.4 -//
    47.5 -//  AttachmentToLocalURLOperation.swift
    47.6 -//  pEpForiOS
    47.7 -//
    47.8 -//  Created by Dirk Zimmermann on 11.04.17.
    47.9 -//  Copyright © 2017 p≡p Security S.A. All rights reserved.
   47.10 -//
   47.11 -
   47.12 -import Foundation
   47.13 -import pEpIOSToolbox
   47.14 -import MessageModel
   47.15 -
   47.16 -//!!!: must go to MM interfaces. 
   47.17 -class AttachmentToLocalURLOperation: Operation {
   47.18 -    var fileURL: URL?
   47.19 -    private var attachment: Attachment
   47.20 -
   47.21 -    init(attachment: Attachment) {
   47.22 -        self.attachment = attachment
   47.23 -        super.init()
   47.24 -    }
   47.25 -
   47.26 -    override func main() {
   47.27 -        let session = Session()
   47.28 -        let safeAttachment = attachment.safeForSession(session)
   47.29 -        session.performAndWait { [weak self] in
   47.30 -            guard let me = self else {
   47.31 -                Log.shared.errorAndCrash("Lost myself")
   47.32 -                return
   47.33 -            }
   47.34 -
   47.35 -            guard let data =  safeAttachment.data else {
   47.36 -                Log.shared.warn("Attachment without data")
   47.37 -                return
   47.38 -            }
   47.39 -            let tmpDirURL =  FileManager.default.temporaryDirectory
   47.40 -            
   47.41 -            let fileName = ( safeAttachment.fileName ?? Constants.defaultFileName).extractFileNameOrCid()
   47.42 -            var theURL = tmpDirURL.appendingPathComponent(fileName)
   47.43 -
   47.44 -            if let mimeType = safeAttachment.mimeType, mimeType == MimeTypeUtils.MimesType.pdf {
   47.45 -                theURL = theURL.appendingPathExtension("pdf")
   47.46 -            }
   47.47 -            do {
   47.48 -                try data.write(to: theURL)
   47.49 -                me.fileURL = theURL
   47.50 -            } catch {
   47.51 -                Log.shared.errorAndCrash(error: error)
   47.52 -            }
   47.53 -        }
   47.54 -    }
   47.55 -}
    48.1 --- a/pEpForiOS/UI/EmailDisplay/Background/AttachmentsViewOperation.swift	Fri Feb 07 12:29:26 2020 +0100
    48.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    48.3 @@ -1,94 +0,0 @@
    48.4 -//
    48.5 -//  AttachmentsViewOperation.swift
    48.6 -//  pEpForiOS
    48.7 -//
    48.8 -//  Created by Dirk Zimmermann on 03.04.17.
    48.9 -//  Copyright © 2017 p≡p Security S.A. All rights reserved.
   48.10 -//
   48.11 -
   48.12 -//!!!: rm this file. Make this an extension of Attachment. Accoring to Message+PEPRatingReevaluation.
   48.13 -import Foundation
   48.14 -
   48.15 -import MessageModel
   48.16 -
   48.17 -class AttachmentsViewOperation: Operation {
   48.18 -    enum AttachmentContainer {
   48.19 -        case imageAttachment(Attachment, UIImage)
   48.20 -        case docAttachment(Attachment)
   48.21 -    }
   48.22 -
   48.23 -//    private let session: Session
   48.24 -    private let mimeTypes: MimeTypeUtils?
   48.25 -    private var message: Message
   48.26 -
   48.27 -    ///The resulting attachments view will appear here.
   48.28 -    var attachmentContainers = [AttachmentContainer]()
   48.29 -
   48.30 -//    /**
   48.31 -//     The number of attachments.
   48.32 -//     */
   48.33 -//    private var attachmentsCount = 0
   48.34 -
   48.35 -    init(mimeTypes: MimeTypeUtils?, message: Message) {
   48.36 -//        self.session = message.session
   48.37 -
   48.38 -        self.message = message
   48.39 -        self.mimeTypes = mimeTypes
   48.40 -        super.init()
   48.41 -
   48.42 -//        session.performAndWait { [weak self] in
   48.43 -//            guard let me = self else {
   48.44 -//                Log.shared.errorAndCrash("Lost myself")
   48.45 -//                return
   48.46 -//            }
   48.47 -//
   48.48 -//            me.attachmentsCount = me.message.viewableAttachments().count
   48.49 -//        }
   48.50 -    }
   48.51 -
   48.52 -    override func main() {
   48.53 -        let session = Session()
   48.54 -        let safeMessage = message.safeForSession(session)
   48.55 -
   48.56 -        session.performAndWait { [weak self] in
   48.57 -            guard let me = self else {
   48.58 -                Log.shared.errorAndCrash("Lost myself")
   48.59 -                return
   48.60 -            }
   48.61 -
   48.62 -            let attachments = safeMessage.viewableAttachments()
   48.63 -            for att in attachments {
   48.64 -                if att.isInlined {
   48.65 -                    // Ignore attachments that are already shown inline in the message body.
   48.66 -                    // Try to verify this by checking if their CID (if any) is mentioned there.
   48.67 -                    // So attachments labeled as inline _are_ shown if
   48.68 -                    //  * they don't have a CID
   48.69 -                    //  * their CID doesn't occur in the HTML body
   48.70 -                    var cidContained = false
   48.71 -                    if let theCid = att.fileName?.extractCid() {
   48.72 -                        cidContained = safeMessage.longMessageFormatted?.contains(
   48.73 -                            find: theCid) ?? false
   48.74 -                    }
   48.75 -                    if cidContained {
   48.76 -                        // seems like this inline attachment is really inline, don't show it
   48.77 -                        continue
   48.78 -                    }
   48.79 -                }
   48.80 -
   48.81 -                let isImage: Bool
   48.82 -                if let mimeType = att.mimeType {
   48.83 -                    isImage = MimeTypeUtils.isImage(mimeType: mimeType)
   48.84 -                } else {
   48.85 -                    isImage = false
   48.86 -                }
   48.87 -                if (isImage),
   48.88 -                    let imgData = att.data,
   48.89 -                    let img = UIImage.image(gifData: imgData) ?? UIImage(data: imgData) {
   48.90 -                    me.attachmentContainers.append(.imageAttachment(att, img))
   48.91 -                } else {
   48.92 -                    me.attachmentContainers.append(.docAttachment(att))
   48.93 -                }
   48.94 -            }
   48.95 -        }
   48.96 -    }
   48.97 -}
    49.1 --- a/pEpForiOS/UI/EmailDisplay/CellAndSections/MailinglistCell.swift	Fri Feb 07 12:29:26 2020 +0100
    49.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    49.3 @@ -1,17 +0,0 @@
    49.4 -//
    49.5 -//  MailinglistCell.swift
    49.6 -//
    49.7 -//  Created by Yves Landert on 21.12.16.
    49.8 -//  Copyright © 2016 appculture AG. All rights reserved.
    49.9 -//
   49.10 -
   49.11 -import UIKit
   49.12 -
   49.13 -import MessageModel
   49.14 -
   49.15 -open class MailinglistCell: MessageCell {
   49.16 -    public override func updateCell(model: ComposeFieldModel, message: Message) {
   49.17 -        super.updateCell(model: model, message: message)
   49.18 -        height = 0
   49.19 -    }
   49.20 -}
    50.1 --- a/pEpForiOS/UI/EmailDisplay/CellAndSections/MessageAttachmentsCell.swift	Fri Feb 07 12:29:26 2020 +0100
    50.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    50.3 @@ -1,68 +0,0 @@
    50.4 -//
    50.5 -//  MessageAttachmentsCell.swift
    50.6 -//  pEpForiOS
    50.7 -//
    50.8 -//  Created by Dirk Zimmermann on 04.04.17.
    50.9 -//  Copyright © 2017 p≡p Security S.A. All rights reserved.
   50.10 -//
   50.11 -
   50.12 -import Foundation
   50.13 -
   50.14 -import MessageModel
   50.15 -
   50.16 -class MessageAttachmentsCell: MessageCell {
   50.17 -    @IBOutlet weak var attachmentsImageView: AttachmentsView!
   50.18 -
   50.19 -    var attachmentsViewHelper = AttachmentsViewHelper()
   50.20 -    var lastMessage: Message?
   50.21 -
   50.22 -    override func awakeFromNib() {
   50.23 -        attachmentsViewHelper.attachmentsImageView = attachmentsImageView
   50.24 -        attachmentsViewHelper.delegate = self
   50.25 -        attachmentsImageView.delegate = self
   50.26 -        selectionStyle = .none
   50.27 -    }
   50.28 -
   50.29 -    public override func updateCell(model: ComposeFieldModel, message: Message) {
   50.30 -        super.updateCell(model: model, message: message)
   50.31 -
   50.32 -        if message.underAttack {
   50.33 -            return
   50.34 -        }
   50.35 -
   50.36 -        if message == lastMessage {
   50.37 -            // Avoid processing the same message over and over again, unless
   50.38 -            // the attachment count changes, which is considered by `==`.
   50.39 -            return
   50.40 -        }
   50.41 -
   50.42 -        attachmentsViewHelper.message = message
   50.43 -        lastMessage = message
   50.44 -
   50.45 -        // Work around auto-layout problems
   50.46 -        if !message.viewableAttachments().isEmpty {
   50.47 -            let cZeroHeight = contentView.heightAnchor.constraint(equalToConstant: 0)
   50.48 -            let cMinimumHeight = contentView.heightAnchor.constraint(greaterThanOrEqualToConstant: 44)
   50.49 -            cZeroHeight.isActive = false
   50.50 -            cMinimumHeight.isActive = true
   50.51 -        }
   50.52 -    }
   50.53 -}
   50.54 -
   50.55 -// MARK: - AttachmentsViewDelegate
   50.56 -
   50.57 -extension MessageAttachmentsCell: AttachmentsViewDelegate {
   50.58 -    func didTap(attachment: Attachment, location: CGPoint, inView: UIView?) {
   50.59 -        (delegate as? MessageAttachmentDelegate)?.didTap(cell: self, attachment: attachment,
   50.60 -                                                         location: location, inView: inView)
   50.61 -    }
   50.62 -}
   50.63 -
   50.64 -// MARK: - AttachmentsViewHelperDelegate
   50.65 -
   50.66 -extension MessageAttachmentsCell: AttachmentsViewHelperDelegate {
   50.67 -    
   50.68 -    func didCreate(attachmentsView: UIView?) {
   50.69 -        (delegate as? MessageContentCellDelegate)?.didUpdate(cell: self, height: 0)
   50.70 -    }
   50.71 -}
    51.1 --- a/pEpForiOS/UI/EmailDisplay/CellAndSections/MessageCell.swift	Fri Feb 07 12:29:26 2020 +0100
    51.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    51.3 @@ -1,48 +0,0 @@
    51.4 -//
    51.5 -//  MessageCell.swift
    51.6 -//
    51.7 -//  Created by Yves Landert on 16.12.16.
    51.8 -//  Copyright © 2016 appculture AG. All rights reserved.
    51.9 -//
   51.10 -
   51.11 -import UIKit
   51.12 -
   51.13 -import MessageModel
   51.14 -
   51.15 -public protocol MessageCellDelegate: class {}
   51.16 -
   51.17 -public protocol MessageContentCellDelegate: MessageCellDelegate {
   51.18 -    func didUpdate(cell: MessageCell, height: CGFloat)
   51.19 -}
   51.20 -
   51.21 -protocol MessageAttachmentDelegate {
   51.22 -    func didTap(cell: MessageCell, attachment: Attachment, location: CGPoint, inView: UIView?)
   51.23 -}
   51.24 -
   51.25 -open class MessageCell: UITableViewCell {
   51.26 -    @IBOutlet weak public var titleLabel: UILabel?
   51.27 -    @IBOutlet weak public var valueLabel: UILabel?
   51.28 -    
   51.29 -    open weak var delegate: MessageCellDelegate?
   51.30 -    
   51.31 -    public var fieldModel: ComposeFieldModel?
   51.32 -    public var message: Message?
   51.33 -    public var isExpanded = false
   51.34 -    public var height: CGFloat = UITableView.automaticDimension
   51.35 -
   51.36 -    /**
   51.37 -     The current `IndexPath`, as last indicated via a call to `updateCell`.
   51.38 -     */
   51.39 -
   51.40 -    override open func awakeFromNib() {
   51.41 -        super.awakeFromNib()
   51.42 -        selectionStyle = .none
   51.43 -    }
   51.44 -    
   51.45 -    public func updateCell(model: ComposeFieldModel, message: Message) {
   51.46 -        fieldModel = model
   51.47 -        if titleLabel != nil {
   51.48 -            titleLabel?.text = fieldModel?.title
   51.49 -        }
   51.50 -    }
   51.51 -}
    52.1 --- a/pEpForiOS/UI/EmailDisplay/CellAndSections/MessageContentCell.swift	Fri Feb 07 12:29:26 2020 +0100
    52.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    52.3 @@ -1,54 +0,0 @@
    52.4 -//
    52.5 -//  MessageContentCell.swift
    52.6 -//
    52.7 -//  Created by Yves Landert on 20.12.16.
    52.8 -//  Copyright © 2016 appculture AG. All rights reserved.
    52.9 -//
   52.10 -
   52.11 -import Foundation
   52.12 -import UIKit
   52.13 -import WebKit
   52.14 -import MessageModel
   52.15 -import PEPObjCAdapterFramework
   52.16 -
   52.17 -open class MessageContentCell: MessageCell {
   52.18 -    @IBOutlet weak var contentText: UITextView!
   52.19 -
   52.20 -    public override func updateCell(model: ComposeFieldModel, message: Message) {
   52.21 -        updateCell(model: model, message: message, clickHandler: nil)
   52.22 -    }
   52.23 -
   52.24 -    func updateCell(model: ComposeFieldModel, message: Message, clickHandler: UITextViewDelegate?) {
   52.25 -        super.updateCell(model: model, message: message)
   52.26 -
   52.27 -        let finalText = NSMutableAttributedString()
   52.28 -        if message.underAttack {
   52.29 -            let status = String.pEpRatingTranslation(pEpRating: .underAttack)
   52.30 -            let messageString = String.localizedStringWithFormat(
   52.31 -                NSLocalizedString(
   52.32 -                    "\n%1$@\n\n%2$@\n\n%3$@\n\nAttachments are disabled.\n\n",
   52.33 -                    comment: "Disabled attachments for a message with status 'under attack'. " +
   52.34 -                    "Placeholders: Title, explanation, suggestion."),
   52.35 -                status.title, status.explanation, status.suggestion)
   52.36 -            finalText.bold(messageString)
   52.37 -        }
   52.38 -
   52.39 -        if let text = message.longMessage?.trimmed() {
   52.40 -            finalText.normal(text)
   52.41 -        } else if let text = message.longMessageFormatted?.attributedStringHtmlToMarkdown() {
   52.42 -            finalText.normal(text)
   52.43 -        } else if message.pEpRating().isUnDecryptable() {
   52.44 -            finalText.normal(NSLocalizedString(
   52.45 -                "This message could not be decrypted.",
   52.46 -                comment: "content that is shown for undecryptable messages"))
   52.47 -        } else {
   52.48 -            // Empty body
   52.49 -            finalText.normal("")
   52.50 -        }
   52.51 -
   52.52 -        contentText.tintColor = UIColor.pEpGreen
   52.53 -        contentText.attributedText = finalText
   52.54 -        contentText.dataDetectorTypes = UIDataDetectorTypes.link
   52.55 -        contentText.delegate = clickHandler
   52.56 -    }
   52.57 -}
    53.1 --- a/pEpForiOS/UI/EmailDisplay/CellAndSections/MessageSenderCell.swift	Fri Feb 07 12:29:26 2020 +0100
    53.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    53.3 @@ -1,32 +0,0 @@
    53.4 -//
    53.5 -//  MessageSenderCell.swift
    53.6 -//  MailComposer
    53.7 -//
    53.8 -//  Created by Yves Landert on 21.12.16.
    53.9 -//  Copyright © 2016 appculture AG. All rights reserved.
   53.10 -//
   53.11 -
   53.12 -import UIKit
   53.13 -import MessageModel
   53.14 -
   53.15 -open class MessageSenderCell: MessageCell {
   53.16 -    
   53.17 -    public override func updateCell(model: ComposeFieldModel, message: Message) {
   53.18 -        super.updateCell(model: model, message: message)
   53.19 -        titleLabel?.text = message.from?.displayString
   53.20 -        
   53.21 -        let attributed = NSMutableAttributedString(
   53.22 -            string: NSLocalizedString("To: ", comment: "Compose field title"))
   53.23 -        let attributes = [
   53.24 -            NSAttributedString.Key.font: UIFont.systemFont(ofSize: 15.0),
   53.25 -            NSAttributedString.Key.foregroundColor: UIColor.lightGray
   53.26 -        ]
   53.27 -        var temp: [String] = []
   53.28 -        message.allRecipients.forEach { (recepient) in
   53.29 -            let recepient = recepient.address
   53.30 -            temp.append(recepient)
   53.31 -        }
   53.32 -        attributed.append(NSAttributedString(string: temp.joined(separator: ", "), attributes: attributes))
   53.33 -        valueLabel?.attributedText = attributed
   53.34 -    }
   53.35 -}
    54.1 --- a/pEpForiOS/UI/EmailDisplay/CellAndSections/MessageSubjectCell.swift	Fri Feb 07 12:29:26 2020 +0100
    54.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    54.3 @@ -1,23 +0,0 @@
    54.4 -//
    54.5 -//  MessageSubjectCell.swift
    54.6 -//
    54.7 -//  Created by Yves Landert on 21.12.16.
    54.8 -//  Copyright © 2016 appculture AG. All rights reserved.
    54.9 -//
   54.10 -
   54.11 -import UIKit
   54.12 -import MessageModel
   54.13 -import pEpIOSToolbox
   54.14 -
   54.15 -open class MessageSubjectCell: MessageCell {
   54.16 -    public override func updateCell(model: ComposeFieldModel, message: Message) {
   54.17 -        super.updateCell(model: model, message: message)
   54.18 -        titleLabel?.text = message.shortMessage
   54.19 -        
   54.20 -        if let originationDate = message.sent {
   54.21 -            UIHelper.putString((originationDate as Date).fullString(), toLabel: valueLabel)
   54.22 -        } else {
   54.23 -            UIHelper.putString(nil, toLabel: valueLabel)
   54.24 -        }
   54.25 -    }
   54.26 -}
    55.1 --- a/pEpForiOS/UI/EmailDisplay/EmailDetailType.swift	Fri Feb 07 12:29:26 2020 +0100
    55.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    55.3 @@ -1,14 +0,0 @@
    55.4 -//
    55.5 -//  EmailDetailType.swift
    55.6 -//  pEp
    55.7 -//
    55.8 -//  Created by Borja González de Pablo on 10/07/2018.
    55.9 -//  Copyright © 2018 p≡p Security S.A. All rights reserved.
   55.10 -//
   55.11 -
   55.12 -import Foundation
   55.13 -
   55.14 -enum EmailDetailType {
   55.15 -    case single
   55.16 -    case thread
   55.17 -}
    56.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    56.2 +++ b/pEpForiOS/UI/EmailDisplay/EmailDetailView/EmailDetailCollectionViewCell.swift	Fri Feb 07 12:31:01 2020 +0100
    56.3 @@ -0,0 +1,38 @@
    56.4 +//
    56.5 +//  EmailDetailCollectionViewCell.swift
    56.6 +//  pEp
    56.7 +//
    56.8 +//  Created by Andreas Buff on 10.12.19.
    56.9 +//  Copyright © 2019 p≡p Security S.A. All rights reserved.
   56.10 +//
   56.11 +
   56.12 +import pEpIOSToolbox
   56.13 +
   56.14 +/// Cell that offers (only) a container to display an (Email)View in.
   56.15 +class EmailDetailCollectionViewCell: UICollectionViewCell {
   56.16 +    @IBOutlet weak var containerView: UIView!
   56.17 +    private weak var containedView: UIView?
   56.18 +
   56.19 +    /// This cell
   56.20 +    public func setContainedView(containedView: UIView) {
   56.21 +        self.containedView = containedView
   56.22 +        containerView.addSubview(containedView)
   56.23 +        containedView.fullSizeInSuperView()
   56.24 +    }
   56.25 +
   56.26 +    override func prepareForReuse() {
   56.27 +        // Remove the previously shown EmailViewController view
   56.28 +        removeContatinedView()
   56.29 +        isSelected = false
   56.30 +    }
   56.31 +}
   56.32 +
   56.33 +// MARK: - Private
   56.34 +
   56.35 +extension EmailDetailCollectionViewCell {
   56.36 +
   56.37 +    private func removeContatinedView() {
   56.38 +        containedView?.removeFromSuperview()
   56.39 +        containedView = nil
   56.40 +    }
   56.41 +}
    57.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    57.2 +++ b/pEpForiOS/UI/EmailDisplay/EmailDetailView/EmailDetailCollectionViewCell.xib	Fri Feb 07 12:31:01 2020 +0100
    57.3 @@ -0,0 +1,40 @@
    57.4 +<?xml version="1.0" encoding="UTF-8"?>
    57.5 +<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
    57.6 +    <device id="retina6_1" orientation="portrait" appearance="light"/>
    57.7 +    <dependencies>
    57.8 +        <deployment identifier="iOS"/>
    57.9 +        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15510"/>
   57.10 +        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
   57.11 +        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
   57.12 +    </dependencies>
   57.13 +    <objects>
   57.14 +        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
   57.15 +        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
   57.16 +        <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="EmailDetailViewCell" id="gTV-IL-0wX" customClass="EmailDetailCollectionViewCell" customModule="pEpForiOS" customModuleProvider="target">
   57.17 +            <rect key="frame" x="0.0" y="0.0" width="390" height="355"/>
   57.18 +            <autoresizingMask key="autoresizingMask"/>
   57.19 +            <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
   57.20 +                <rect key="frame" x="0.0" y="0.0" width="390" height="355"/>
   57.21 +                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
   57.22 +                <subviews>
   57.23 +                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="f0n-D0-Fwe">
   57.24 +                        <rect key="frame" x="0.0" y="0.0" width="390" height="355"/>
   57.25 +                        <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
   57.26 +                    </view>
   57.27 +                </subviews>
   57.28 +            </view>
   57.29 +            <constraints>
   57.30 +                <constraint firstItem="f0n-D0-Fwe" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="1g9-gB-90y"/>
   57.31 +                <constraint firstAttribute="trailing" secondItem="f0n-D0-Fwe" secondAttribute="trailing" id="76d-sG-UOn"/>
   57.32 +                <constraint firstItem="f0n-D0-Fwe" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" id="qFW-EW-vlh"/>
   57.33 +                <constraint firstAttribute="bottom" secondItem="f0n-D0-Fwe" secondAttribute="bottom" id="zc5-Ce-nFv"/>
   57.34 +            </constraints>
   57.35 +            <viewLayoutGuide key="safeArea" id="ZTg-uK-7eu"/>
   57.36 +            <size key="customSize" width="390" height="355"/>
   57.37 +            <connections>
   57.38 +                <outlet property="containerView" destination="f0n-D0-Fwe" id="ebY-I5-214"/>
   57.39 +            </connections>
   57.40 +            <point key="canvasLocation" x="384.05797101449281" y="189.84375"/>
   57.41 +        </collectionViewCell>
   57.42 +    </objects>
   57.43 +</document>
    58.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    58.2 +++ b/pEpForiOS/UI/EmailDisplay/EmailDetailView/EmailDetailViewController.swift	Fri Feb 07 12:31:01 2020 +0100
    58.3 @@ -0,0 +1,802 @@
    58.4 +//
    58.5 +//  EmailDetailViewController.swift
    58.6 +//  pEp
    58.7 +//
    58.8 +//  Created by Andreas Buff on 04.12.19.
    58.9 +//  Copyright © 2019 p≡p Security S.A. All rights reserved.
   58.10 +//
   58.11 +
   58.12 +import UIKit
   58.13 +import QuickLook
   58.14 +import pEpIOSToolbox
   58.15 +
   58.16 +// Represents the a list of mails showing one mail with all details in full screen.
   58.17 +class EmailDetailViewController: BaseViewController {
   58.18 +    static private let cellXibName = "EmailDetailCollectionViewCell"
   58.19 +    static private let cellId = "EmailDetailViewCell"
   58.20 +    /// Collects all QueryResultsDelegate reported changes to call them in one CollectionView
   58.21 +    /// batchUpdate.
   58.22 +    private var collectionViewUpdateTasks: [()->Void] = []
   58.23 +    /// EmailViewControllers of currently used cells
   58.24 +    private var emailSubViewControllers = [EmailViewController]()
   58.25 +    /// Stuff that must be done once only in viewWillAppear
   58.26 +    private var doOnce: (()-> Void)?
   58.27 +
   58.28 +    private var pdfPreviewUrl: URL?
   58.29 +
   58.30 +    @IBOutlet weak var nextButton: UIBarButtonItem?
   58.31 +    @IBOutlet weak var previousButton: UIBarButtonItem?
   58.32 +    @IBOutlet weak var flagButton: UIBarButtonItem!
   58.33 +    @IBOutlet weak var destructiveButton: UIBarButtonItem!
   58.34 +    @IBOutlet weak var replyButton: UIBarButtonItem!
   58.35 +    @IBOutlet weak var moveToFolderButton: UIBarButtonItem!
   58.36 +    @IBOutlet weak var collectionView: UICollectionView!
   58.37 +
   58.38 +    /// IndexPath to show on load
   58.39 +    var firstItemToShow: IndexPath?
   58.40 +
   58.41 +    var viewModel: EmailDetailViewModel? {
   58.42 +        didSet {
   58.43 +            viewModel?.delegate = self
   58.44 +        }
   58.45 +    }
   58.46 +
   58.47 +    override func viewDidLoad() {
   58.48 +        super.viewDidLoad()
   58.49 +        setup()
   58.50 +    }
   58.51 +
   58.52 +    override func viewWillAppear(_ animated: Bool) {
   58.53 +        super.viewWillAppear(animated)
   58.54 +        doOnce?()
   58.55 +        doOnce = nil
   58.56 +    }
   58.57 +
   58.58 +    override func viewWillLayoutSubviews() {
   58.59 +        super.viewDidLayoutSubviews()
   58.60 +        // Re-layout cells after device orientaion change
   58.61 +        collectionView.collectionViewLayout.invalidateLayout()
   58.62 +    }
   58.63 +
   58.64 +    deinit {
   58.65 +        NotificationCenter.default.removeObserver(self)
   58.66 +    }
   58.67 +
   58.68 +    // MARK: - Target & Action
   58.69 +
   58.70 +    @IBAction func flagButtonPressed(_ sender: UIBarButtonItem) {
   58.71 +        guard let vm = viewModel else {
   58.72 +            Log.shared.errorAndCrash("No VM")
   58.73 +            return
   58.74 +        }
   58.75 +        guard let indexPath = indexPathOfCurrentlyVisibleCell else {
   58.76 +            Log.shared.errorAndCrash("Nothing shown?")
   58.77 +            return
   58.78 +        }
   58.79 +        vm.handleFlagButtonPress(for: indexPath)
   58.80 +    }
   58.81 +
   58.82 +    @IBAction func moveToFolderButtonPressed(_ sender: UIBarButtonItem) {
   58.83 +        performSegue(withIdentifier: .segueShowMoveToFolder, sender: self)
   58.84 +    }
   58.85 +
   58.86 +    @IBAction func destructiveButtonPressed(_ sender: UIBarButtonItem) {
   58.87 +        guard let vm = viewModel else {
   58.88 +            Log.shared.errorAndCrash("No VM")
   58.89 +            return
   58.90 +        }
   58.91 +        guard let indexPath = indexPathOfCurrentlyVisibleCell else {
   58.92 +            Log.shared.errorAndCrash("Nothing shown?")
   58.93 +            return
   58.94 +        }
   58.95 +        vm.handleDestructiveButtonPress(for: indexPath)
   58.96 +    }
   58.97 +
   58.98 +    @IBAction func replyButtonPressed(_ sender: UIBarButtonItem) {
   58.99 +        // The ReplyAllPossibleChecker() should be pushed into the view model
  58.100 +        // as soon as there is one.
  58.101 +        guard
  58.102 +            let vm = viewModel,
  58.103 +            let indexPath = indexPathOfCurrentlyVisibleCell,
  58.104 +            let replyAllChecker = vm.replyAllPossibleChecker(forItemAt: indexPath)
  58.105 +            else {
  58.106 +                Log.shared.errorAndCrash("Invalid state")
  58.107 +                return
  58.108 +        }
  58.109 +
  58.110 +        let alert = ReplyAlertCreator(replyAllChecker: replyAllChecker)
  58.111 +            .withReplyOption { [weak self] action in
  58.112 +                guard let me = self else {
  58.113 +                    Log.shared.errorAndCrash("Lost MySelf")
  58.114 +                    return
  58.115 +                }
  58.116 +                me.performSegue(withIdentifier: .segueReplyFrom , sender: self)
  58.117 +        }.withReplyAllOption() { [weak self] action in
  58.118 +            guard let me = self else {
  58.119 +                Log.shared.errorAndCrash("Lost MySelf")
  58.120 +                return
  58.121 +            }
  58.122 +            me.performSegue(withIdentifier: .segueReplyAllForm , sender: self)
  58.123 +        }.withFordwardOption { [weak self] action in
  58.124 +            guard let me = self else {
  58.125 +                Log.shared.errorAndCrash("Lost MySelf")
  58.126 +                return
  58.127 +            }
  58.128 +            me.performSegue(withIdentifier: .segueForward , sender: self)
  58.129 +        }.withCancelOption()
  58.130 +            .build()
  58.131 +
  58.132 +        if let popoverPresentationController = alert.popoverPresentationController {
  58.133 +            popoverPresentationController.barButtonItem = sender
  58.134 +        }
  58.135 +
  58.136 +        present(alert, animated: true, completion: nil)
  58.137 +    }
  58.138 +
  58.139 +    @IBAction func previousButtonPressed(_ sender: UIBarButtonItem) {
  58.140 +        showPreviousIfAny()
  58.141 +    }
  58.142 +    
  58.143 +    @IBAction func nextButtonPressed(_ sender: UIBarButtonItem) {
  58.144 +        showNextIfAny()
  58.145 +    }
  58.146 +}
  58.147 +
  58.148 +// MARK: - Private
  58.149 +
  58.150 +extension EmailDetailViewController {
  58.151 +
  58.152 +    private func setup() {
  58.153 +        viewModel?.delegate = self
  58.154 +        setupCollectionView()
  58.155 +        registerNotifications()
  58.156 +        setupToolbar()
  58.157 +        doOnce = { [weak self] in
  58.158 +            guard let me = self else {
  58.159 +                Log.shared.errorAndCrash("Lost myself")
  58.160 +                return
  58.161 +            }
  58.162 +            me.viewModel?.startMonitoring()
  58.163 +            me.collectionView.reloadData()
  58.164 +        }
  58.165 +    }
  58.166 +
  58.167 +    private func setupCollectionView() {
  58.168 +        collectionView.delegate = self
  58.169 +        collectionView.dataSource = self
  58.170 +        collectionView.register(UINib(nibName: EmailDetailViewController.cellXibName,
  58.171 +                                      bundle: nil),
  58.172 +                                forCellWithReuseIdentifier: EmailDetailViewController.cellId)
  58.173 +    }
  58.174 +
  58.175 +    private func showNextIfAny() {
  58.176 +        guard
  58.177 +            let indexPathForCurrentlyVisibleCell = indexPathOfCurrentlyVisibleCell,
  58.178 +            thereIsANextMessageToShow
  58.179 +            else {
  58.180 +                // No mail to show
  58.181 +                return
  58.182 +        }
  58.183 +        let nextIndexPath = IndexPath(item: indexPathForCurrentlyVisibleCell.item + 1,
  58.184 +                                      section: indexPathForCurrentlyVisibleCell.section)
  58.185 +        scroll(to: nextIndexPath)
  58.186 +    }
  58.187 +
  58.188 +    private func showPreviousIfAny() {
  58.189 +        guard
  58.190 +            let indexPathForCurrentlyVisibleCell = indexPathOfCurrentlyVisibleCell,
  58.191 +            thereIsAPreviousMessageToShow
  58.192 +            else {
  58.193 +                // No mail to show
  58.194 +                return
  58.195 +        }
  58.196 +        let nextIndexPath = IndexPath(item: indexPathForCurrentlyVisibleCell.item - 1,
  58.197 +                                      section: indexPathForCurrentlyVisibleCell.section)
  58.198 +        scroll(to: nextIndexPath)
  58.199 +    }
  58.200 +
  58.201 +    @objc
  58.202 +    private func showHandshakeView(gestureRecognizer: UITapGestureRecognizer? = nil) {
  58.203 +        if onlySplitViewMasterIsShown {
  58.204 +            performSegue(withIdentifier: .segueHandshakeCollapsed, sender: self)
  58.205 +
  58.206 +        } else {
  58.207 +            performSegue(withIdentifier: .segueHandshake, sender: self)
  58.208 +        }
  58.209 +    }
  58.210 +
  58.211 +    private var indexPathOfCurrentlyVisibleCell: IndexPath? {
  58.212 +        // We are manually computing the currently shown indexPath as
  58.213 +        // collectionView.indexPathsForVisibleItems oftern contains more then one (i.e. 2) indexpaths.
  58.214 +        let visibleRect = CGRect(origin: collectionView.contentOffset,
  58.215 +                                 size: collectionView.bounds.size)
  58.216 +        let visiblePoint = CGPoint(x: visibleRect.midX,
  58.217 +                                   y: visibleRect.midY)
  58.218 +        let visibleIndexPath = collectionView.indexPathForItem(at: visiblePoint)
  58.219 +        return visibleIndexPath
  58.220 +    }
  58.221 +
  58.222 +    /// Makes sure the message the user is currently viewing is still shown after collection view
  58.223 +    /// updates (which may modify the visible cell by removing or inserting a mails with
  58.224 +    /// row num < currently shown).
  58.225 +    private func scrollToLastViewedCell() {
  58.226 +        guard
  58.227 +            let vm = viewModel,
  58.228 +            let indexPath = vm.indexPathForCellDisplayedBeforeUpdating else {
  58.229 +                // The previously shown message might have been deleted.
  58.230 +                // Do nothing ...
  58.231 +                return
  58.232 +        }
  58.233 +        collectionView?.scrollToItem(at: indexPath,
  58.234 +                                     at: .centeredHorizontally,
  58.235 +                                     animated: false)
  58.236 +    }
  58.237 +
  58.238 +    private var thereIsANextMessageToShow: Bool {
  58.239 +        guard let indexPathForCurrentlyVisibleCell = indexPathOfCurrentlyVisibleCell else {
  58.240 +            // No mail to show
  58.241 +            return false
  58.242 +        }
  58.243 +        guard let vm = viewModel else {
  58.244 +            Log.shared.errorAndCrash("No VM")
  58.245 +            return false
  58.246 +        }
  58.247 +        return (indexPathForCurrentlyVisibleCell.row + 1) < vm.rowCount
  58.248 +    }
  58.249 +
  58.250 +    private var thereIsAPreviousMessageToShow: Bool {
  58.251 +        guard let indexPathForCurrentlyVisibleCell = indexPathOfCurrentlyVisibleCell else {
  58.252 +            // No mail to show
  58.253 +            return false
  58.254 +        }
  58.255 +
  58.256 +        return (indexPathForCurrentlyVisibleCell.row - 1) >= 0
  58.257 +    }
  58.258 +
  58.259 +    private func scroll(to indexPath: IndexPath,
  58.260 +                        at: UICollectionView.ScrollPosition = .centeredHorizontally,
  58.261 +                        animated: Bool = true) {
  58.262 +        collectionView.scrollToItem(at: indexPath,
  58.263 +                                    at: at,
  58.264 +                                    animated: animated)
  58.265 +    }
  58.266 +
  58.267 +    private func configureView() {
  58.268 +        // Make sure the NavigationBar is shown, even if the previous view has hidden it.
  58.269 +        navigationController?.setNavigationBarHidden(false, animated: false) //XAVIER: rm NC in storyboard after new SplitView handling approach is in.
  58.270 +
  58.271 +        //ToolBar
  58.272 +        if splitViewController != nil {
  58.273 +            if onlySplitViewMasterIsShown {
  58.274 +                navigationController?.setToolbarHidden(false, animated: false)
  58.275 +            } else {
  58.276 +                navigationController?.setToolbarHidden(true, animated: false)
  58.277 +            }
  58.278 +        }
  58.279 +        guard let vm = viewModel else {
  58.280 +            Log.shared.errorAndCrash("No VM")
  58.281 +            return
  58.282 +        }
  58.283 +
  58.284 +        destructiveButton.image = vm.destructiveButtonIcon(forMessageAt: indexPathOfCurrentlyVisibleCell)
  58.285 +        flagButton.image = vm.flagButtonIcon(forMessageAt: indexPathOfCurrentlyVisibleCell)
  58.286 +
  58.287 +        previousButton?.isEnabled = thereIsAPreviousMessageToShow
  58.288 +        nextButton?.isEnabled = thereIsANextMessageToShow
  58.289 +
  58.290 +        showPepRating()
  58.291 +    }
  58.292 +
  58.293 +    private func showPepRating() {
  58.294 +        guard let vm = viewModel else {
  58.295 +            Log.shared.errorAndCrash("No VM")
  58.296 +            return
  58.297 +        }
  58.298 +        guard let indexPath = indexPathOfCurrentlyVisibleCell else {
  58.299 +            // List is empty. That is ok. The user might have deleted the last shown message.
  58.300 +            return
  58.301 +        }
  58.302 +        guard let ratingView = showNavigationBarSecurityBadge(pEpRating: vm.pEpRating(forItemAt: indexPath)) else {
  58.303 +            // Nothing to show for current message
  58.304 +            return
  58.305 +        }
  58.306 +
  58.307 +        if vm.shouldShowPrivacyStatus(forItemAt: indexPath) {
  58.308 +            let tapGestureRecognizer = UITapGestureRecognizer(target: self,
  58.309 +                                                              action: #selector(showHandshakeView(gestureRecognizer:)))
  58.310 +            ratingView.addGestureRecognizer(tapGestureRecognizer)
  58.311 +        }
  58.312 +    }
  58.313 +
  58.314 +    private func registerNotifications() {
  58.315 +        NotificationCenter.default.addObserver(self,
  58.316 +                                               selector: #selector(EmailDetailViewController.rotated),
  58.317 +                                               name: UIDevice.orientationDidChangeNotification,
  58.318 +                                               object: nil)
  58.319 +    }
  58.320 +
  58.321 +    @objc
  58.322 +    private func rotated() {
  58.323 +        // Works around a UI glitch: When !onlySplitViewMasterIsShown, the colletionView scroll
  58.324 +        // position is inbetween two cells after orientation change.
  58.325 +        scrollToLastViewedCell()
  58.326 +    }
  58.327 +
  58.328 +    private func setupToolbar() {
  58.329 +        let pEpButton = UIBarButtonItem.getPEPButton(action: #selector(showPepActions(sender:)),
  58.330 +                                                     target: self)
  58.331 +        let flexibleSpace: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace,
  58.332 +                                                             target: nil,
  58.333 +                                                             action: nil)
  58.334 +        toolbarItems?.append(contentsOf: [flexibleSpace, pEpButton])
  58.335 +        if !(onlySplitViewMasterIsShown) {
  58.336 +            navigationItem.rightBarButtonItems = toolbarItems
  58.337 +        }
  58.338 +    }
  58.339 +
  58.340 +    // Removes all EmailViewController that are not connected to a cell any more.
  58.341 +    private func releaseUnusedSubViewControllers() {
  58.342 +        emailSubViewControllers = emailSubViewControllers.filter { $0.view.superview != nil }
  58.343 +    }
  58.344 +
  58.345 +    @objc
  58.346 +    private func showPepActions(sender: UIBarButtonItem) {
  58.347 +        guard let vm = viewModel else {
  58.348 +            Log.shared.errorAndCrash("No VM")
  58.349 +            return
  58.350 +        }
  58.351 +        guard let indexPath = indexPathOfCurrentlyVisibleCell else {
  58.352 +            Log.shared.errorAndCrash("Nothing shown?")
  58.353 +            return
  58.354 +        }
  58.355 +
  58.356 +        let actionSheetController = UIAlertController.pEpAlertController(preferredStyle: .actionSheet)
  58.357 +
  58.358 +        if vm.shouldShowPrivacyStatus(forItemAt:indexPath),
  58.359 +            let handshakeAction = showHandshakeViewAction() {
  58.360 +            actionSheetController.addAction(handshakeAction)
  58.361 +        }
  58.362 +        actionSheetController.addAction(tutorialAction())
  58.363 +        actionSheetController.addAction(showSettingsAction())
  58.364 +
  58.365 +        let cancelAction = UIAlertAction(
  58.366 +            title: NSLocalizedString("Cancel", comment: "possible private status action"),
  58.367 +            style: .cancel) { (action) in }
  58.368 +        actionSheetController.addAction(cancelAction)
  58.369 +
  58.370 +        if splitViewController != nil, !onlySplitViewMasterIsShown {
  58.371 +            actionSheetController.popoverPresentationController?.barButtonItem = sender
  58.372 +        }
  58.373 +        present(actionSheetController, animated: true)
  58.374 +    }
  58.375 +
  58.376 +    private func showSettingsAction() -> UIAlertAction {
  58.377 +        let action = UIAlertAction(
  58.378 +            title: NSLocalizedString("Settings", comment: "acction sheet title 2"),
  58.379 +            style: .default) { [weak self] (action) in
  58.380 +                guard let me = self else {
  58.381 +                    Log.shared.errorAndCrash(message: "lost myself")
  58.382 +                    return
  58.383 +                }
  58.384 +                me.showSettingsViewController()
  58.385 +        }
  58.386 +        return action
  58.387 +    }
  58.388 +
  58.389 +    private func tutorialAction() -> UIAlertAction{
  58.390 +        return UIAlertAction(
  58.391 +            title: NSLocalizedString("Tutorial", comment: "show tutorial from compose view"),
  58.392 +            style: .default) { _ in
  58.393 +                TutorialWizardViewController.presentTutorialWizard(viewController: self)
  58.394 +        }
  58.395 +    }
  58.396 +
  58.397 +    private func showHandshakeViewAction() -> UIAlertAction? {
  58.398 +        let action = UIAlertAction(title: NSLocalizedString("Privacy Status",
  58.399 +                                                            comment: "action sheet title 1"),
  58.400 +                                   style: .default) { [weak self] (action) in
  58.401 +                                    guard let me = self else {
  58.402 +                                        Log.shared.errorAndCrash(message: "lost myself")
  58.403 +                                        return
  58.404 +                                    }
  58.405 +                                    me.showHandshakeView()
  58.406 +        }
  58.407 +
  58.408 +        return action
  58.409 +    }
  58.410 +
  58.411 +    @objc
  58.412 +    private func showHandshakeScreen() {
  58.413 +        splitViewController?.preferredDisplayMode = .allVisible
  58.414 +        guard let nav = splitViewController?.viewControllers.first as? UINavigationController,
  58.415 +            let vc = nav.topViewController else {
  58.416 +                return
  58.417 +        }
  58.418 +        UIUtils.presentSettings(on: vc, appConfig: appConfig)
  58.419 +    }
  58.420 +
  58.421 +    @objc
  58.422 +    private func showSettingsViewController() {
  58.423 +        splitViewController?.preferredDisplayMode = .allVisible
  58.424 +        guard let nav = splitViewController?.viewControllers.first as? UINavigationController,
  58.425 +            let vc = nav.topViewController else {
  58.426 +                return
  58.427 +        }
  58.428 +        UIUtils.presentSettings(on: vc, appConfig: appConfig)
  58.429 +    }
  58.430 +
  58.431 +    private func setupEmailViewController(forRowAt indexPath: IndexPath) -> EmailViewController? {
  58.432 +        guard
  58.433 +            let vm = viewModel,
  58.434 +            let createe = storyboard?.instantiateViewController(withIdentifier: EmailViewController.storyboardId) as? EmailViewController
  58.435 +            else {
  58.436 +                Log.shared.errorAndCrash("No V[M|C]")
  58.437 +                return nil
  58.438 +        }
  58.439 +        createe.appConfig = appConfig
  58.440 +        createe.message = vm.message(representedByRowAt: indexPath) //!!!: EmailVC should have a VM which should be created in our VM. This VC should not be aware of `Message`s!
  58.441 +        createe.delegate = self
  58.442 +        emailSubViewControllers.append(createe)
  58.443 +
  58.444 +        return createe
  58.445 +    }
  58.446 +}
  58.447 +
  58.448 +// MARK: - UICollectionViewDelegate
  58.449 +
  58.450 +extension EmailDetailViewController: UICollectionViewDelegate {
  58.451 +
  58.452 +    func collectionView(_ collectionView: UICollectionView,
  58.453 +                        willDisplay cell: UICollectionViewCell,
  58.454 +                        forItemAt indexPath: IndexPath) {
  58.455 +        // Scroll to show message selected by previous (EmailList) view
  58.456 +        guard let indexToScrollTo = firstItemToShow else {
  58.457 +            // Is not first load.
  58.458 +            // Do nothing
  58.459 +            return
  58.460 +        }
  58.461 +        // On first load only: Display message selected by user in previous VC
  58.462 +        collectionView.scrollToItem(at: indexToScrollTo, at: .left, animated: false)
  58.463 +        firstItemToShow = nil
  58.464 +        guard
  58.465 +            let vm = viewModel,
  58.466 +            let currentlyVisibledIdxPth = indexPathOfCurrentlyVisibleCell else {
  58.467 +                Log.shared.errorAndCrash("Invalid state")
  58.468 +                return
  58.469 +        }
  58.470 +        vm.handleEmailShown(forItemAt: currentlyVisibledIdxPth)
  58.471 +        configureView()
  58.472 +    }
  58.473 +}
  58.474 +
  58.475 +// MARK: - UICollectionViewDataSource
  58.476 +
  58.477 +extension EmailDetailViewController: UICollectionViewDataSource {
  58.478 +    func collectionView(_ collectionView: UICollectionView,
  58.479 +                        numberOfItemsInSection section: Int) -> Int {
  58.480 +        return viewModel?.rowCount ?? 0
  58.481 +    }
  58.482 +
  58.483 +    func collectionView(_ collectionView: UICollectionView,
  58.484 +                        cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
  58.485 +        releaseUnusedSubViewControllers()
  58.486 +
  58.487 +        guard
  58.488 +            let cell =
  58.489 +            collectionView.dequeueReusableCell(withReuseIdentifier: EmailDetailViewController.cellId,
  58.490 +                                               for: indexPath) as? EmailDetailCollectionViewCell,
  58.491 +            let emailViewController = setupEmailViewController(forRowAt: indexPath)
  58.492 +            else {
  58.493 +                Log.shared.errorAndCrash("Error setting up cell")
  58.494 +                return collectionView.dequeueReusableCell(withReuseIdentifier: EmailDetailViewController.cellId,
  58.495 +                                                          for: indexPath)
  58.496 +        }
  58.497 +        cell.setContainedView(containedView: emailViewController.view)
  58.498 +
  58.499 +        return cell
  58.500 +    }
  58.501 +}
  58.502 +
  58.503 +// MARK: - UICollectionViewDelegateFlowLayout
  58.504 +
  58.505 +extension EmailDetailViewController: UICollectionViewDelegateFlowLayout {
  58.506 +
  58.507 +    /// Make cell size == collection view size
  58.508 +    func collectionView(_ collectionView: UICollectionView,
  58.509 +                        layout collectionViewLayout: UICollectionViewLayout,
  58.510 +                        sizeForItemAt indexPath: IndexPath) -> CGSize {
  58.511 +        return collectionView.frame.size
  58.512 +    }
  58.513 +}
  58.514 +
  58.515 +extension EmailDetailViewController: UIScrollViewDelegate {
  58.516 +    // Called after programatically triggered scrollling animation ended.
  58.517 +    func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
  58.518 +        guard
  58.519 +            let vm = viewModel,
  58.520 +            let indexPath = indexPathOfCurrentlyVisibleCell else {
  58.521 +                Log.shared.errorAndCrash("Invalid state")
  58.522 +                return
  58.523 +        }
  58.524 +        vm.handleEmailShown(forItemAt: indexPath)
  58.525 +        configureView()
  58.526 +    }
  58.527 +
  58.528 +    // Called after scrollling animation  triggered by user ended.
  58.529 +    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
  58.530 +        guard
  58.531 +            let vm = viewModel,
  58.532 +            let indexPath = indexPathOfCurrentlyVisibleCell else {
  58.533 +                // No cells shown any more. Can happen, is valid.
  58.534 +                return
  58.535 +        }
  58.536 +        vm.handleEmailShown(forItemAt: indexPath)
  58.537 +        configureView()
  58.538 +    }
  58.539 +}
  58.540 +
  58.541 +// MARK: - SegueHandlerType
  58.542 +
  58.543 +extension EmailDetailViewController: SegueHandlerType {
  58.544 +
  58.545 +    enum SegueIdentifier: String {
  58.546 +        case segueReplyFrom
  58.547 +        case segueReplyAllForm
  58.548 +        case segueForward
  58.549 +        case segueHandshake
  58.550 +        case segueHandshakeCollapsed
  58.551 +        case segueShowMoveToFolder
  58.552 +        case noSegue
  58.553 +    }
  58.554 +
  58.555 +    private func composeMode(for segueId: SegueIdentifier) -> ComposeUtil.ComposeMode {
  58.556 +        if segueId == .segueReplyFrom {
  58.557 +            return .replyFrom
  58.558 +        } else if segueId == .segueReplyAllForm {
  58.559 +            return  .replyAll
  58.560 +        } else if segueId == .segueForward {
  58.561 +            return  .forward
  58.562 +        } else {
  58.563 +            Log.shared.errorAndCrash("Unsupported input")
  58.564 +            return .replyFrom
  58.565 +        }
  58.566 +    }
  58.567 +
  58.568 +    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
  58.569 +        guard
  58.570 +            let vm = viewModel,
  58.571 +            let indexPath = indexPathOfCurrentlyVisibleCell
  58.572 +            else {
  58.573 +                Log.shared.errorAndCrash("Invalid state")
  58.574 +                return
  58.575 +        }
  58.576 +        let theId = segueIdentifier(for: segue)
  58.577 +        switch theId {
  58.578 +        case .segueReplyFrom, .segueReplyAllForm, .segueForward:
  58.579 +            guard  let nav = segue.destination as? UINavigationController,
  58.580 +                let destination = nav.topViewController as? ComposeTableViewController else {
  58.581 +                    Log.shared.errorAndCrash("No DVC?")
  58.582 +                    break
  58.583 +            }
  58.584 +            destination.appConfig = appConfig
  58.585 +            destination.viewModel = vm.composeViewModel(forMessageRepresentedByItemAt: indexPath,
  58.586 +                                                        composeMode: composeMode(for: theId))
  58.587 +        case .segueShowMoveToFolder:
  58.588 +            guard  let nav = segue.destination as? UINavigationController,
  58.589 +                let destination = nav.topViewController as? MoveToAccountViewController else {
  58.590 +                    Log.shared.errorAndCrash("No DVC?")
  58.591 +                    break
  58.592 +            }
  58.593 +            destination.appConfig = appConfig
  58.594 +            destination.viewModel = viewModel?.getMoveToFolderViewModel(forMessageRepresentedByItemAt: indexPath)
  58.595 +        case .segueHandshake, .segueHandshakeCollapsed:
  58.596 +            guard let nv = segue.destination as? UINavigationController,
  58.597 +                let vc = nv.topViewController as? HandshakeViewController else {
  58.598 +                    Log.shared.errorAndCrash("No DVC?")
  58.599 +                    break
  58.600 +            }
  58.601 +
  58.602 +            guard let message = vm.message(representedByRowAt: indexPath) else {
  58.603 +                Log.shared.errorAndCrash("No message")
  58.604 +                return
  58.605 +            }
  58.606 +
  58.607 +            //as we need a view to be source of the popover and title view is not always present.
  58.608 +            //we directly use the navigation bar view.
  58.609 +            nv.popoverPresentationController?.delegate = self
  58.610 +            nv.popoverPresentationController?.sourceView = nv.view
  58.611 +            nv.popoverPresentationController?.sourceRect = CGRect(x: nv.view.bounds.midX,
  58.612 +                                                                  y: nv.view.bounds.midY,
  58.613 +                                                                  width: 0,
  58.614 +                                                                  height: 0)
  58.615 +            vc.appConfig = appConfig
  58.616 +            vc.message = message
  58.617 +            break
  58.618 +        case .noSegue:
  58.619 +            break
  58.620 +        }
  58.621 +    }
  58.622 +}
  58.623 +
  58.624 +// MARK: - UIPopoverPresentationControllerDelegate
  58.625 +
  58.626 +extension EmailDetailViewController: UIPopoverPresentationControllerDelegate {
  58.627 +
  58.628 +    func popoverPresentationController(_ popoverPresentationController: UIPopoverPresentationController,
  58.629 +                                       willRepositionPopoverTo rect: UnsafeMutablePointer<CGRect>,
  58.630 +                                       in view: AutoreleasingUnsafeMutablePointer<UIView>) {
  58.631 +
  58.632 +        guard let titleView = navigationItem.titleView else {
  58.633 +            return
  58.634 +        }
  58.635 +
  58.636 +        rect.initialize(to: CGRect(x:titleView.bounds.midY,
  58.637 +                                   y: titleView.bounds.midX,
  58.638 +                                   width:0,
  58.639 +                                   height:0))
  58.640 +        view.pointee = titleView
  58.641 +
  58.642 +    }
  58.643 +}
  58.644 +
  58.645 +// MARK: - EmailDetailViewModelDelegate
  58.646 +
  58.647 +/// FetchedResultsController (FRC) (und thus QueryResults and subclasses) delegate methods are
  58.648 +/// designed for usage with UITableView methods like willUpdate & didupdate. As UICollectionView
  58.649 +/// does not offer those methods but uses batchUpdate we are collecting the update tasks and run
  58.650 +/// them all in one batchUpdate.
  58.651 +/// - note: FRC does have callbacks for batchUpdate starting from iOS13. Remove this class and use
  58.652 +///         the batchupdate delegte methods of FRC directly after iOS12 support is dropped.
  58.653 +extension EmailDetailViewController: EmailDetailViewModelDelegate {
  58.654 +
  58.655 +    func isNotUndecryptableAnyMore(indexPath: IndexPath) {
  58.656 +        addUpdateTask { [weak self] in
  58.657 +            guard let me = self else {
  58.658 +                Log.shared.errorAndCrash("Lost myself")
  58.659 +                return
  58.660 +            }
  58.661 +            me.collectionView?.reloadItems(at: [indexPath])
  58.662 +        }
  58.663 +    }
  58.664 +
  58.665 +    func emailListViewModel(viewModel: EmailDisplayViewModel,
  58.666 +                            didInsertDataAt indexPaths: [IndexPath]) {
  58.667 +        addUpdateTask { [weak self] in
  58.668 +            guard let me = self else {
  58.669 +                Log.shared.errorAndCrash("Lost myself")
  58.670 +                return
  58.671 +            }
  58.672 +            me.collectionView?.insertItems(at: indexPaths)
  58.673 +        }
  58.674 +    }
  58.675 +
  58.676 +    func emailListViewModel(viewModel: EmailDisplayViewModel,
  58.677 +                            didUpdateDataAt indexPaths: [IndexPath]) {
  58.678 +        addUpdateTask { [weak self] in
  58.679 +            guard let me = self else {
  58.680 +                Log.shared.errorAndCrash("Lost myself")
  58.681 +                return
  58.682 +            }
  58.683 +            me.configureView()
  58.684 +        }
  58.685 +    }
  58.686 +
  58.687 +    func emailListViewModel(viewModel: EmailDisplayViewModel,
  58.688 +                            didRemoveDataAt indexPaths: [IndexPath]) {
  58.689 +        addUpdateTask { [weak self] in
  58.690 +            guard let me = self else {
  58.691 +                Log.shared.errorAndCrash("Lost myself")
  58.692 +                return
  58.693 +            }
  58.694 +            me.collectionView?.deleteItems(at: indexPaths)
  58.695 +        }
  58.696 +    }
  58.697 +
  58.698 +    func emailListViewModel(viewModel: EmailDisplayViewModel,
  58.699 +                            didMoveData atIndexPath: IndexPath,
  58.700 +                            toIndexPath: IndexPath) {
  58.701 +        addUpdateTask { [weak self] in
  58.702 +            guard let me = self else {
  58.703 +                Log.shared.errorAndCrash("Lost myself")
  58.704 +                return
  58.705 +            }
  58.706 +            me.collectionView?.moveItem(at: atIndexPath, to: toIndexPath)
  58.707 +        }
  58.708 +    }
  58.709 +
  58.710 +    func willReceiveUpdates(viewModel: EmailDisplayViewModel) {
  58.711 +        guard collectionViewUpdateTasks.count == 0 else {
  58.712 +            Log.shared.errorAndCrash("We expect all updates done before `willReceiveUpdates` is called again.")
  58.713 +            return
  58.714 +        }
  58.715 +        // Do nothing
  58.716 +    }
  58.717 +
  58.718 +    func allUpdatesReceived(viewModel: EmailDisplayViewModel) {
  58.719 +        // Perform updates ...
  58.720 +        let performChangesBlock = { [weak self] in
  58.721 +            guard let me = self else {
  58.722 +                Log.shared.errorAndCrash("Lost myself")
  58.723 +                return
  58.724 +            }
  58.725 +            let updateTasksToRun = Array(me.collectionViewUpdateTasks)
  58.726 +            me.collectionViewUpdateTasks.removeAll()
  58.727 +            updateTasksToRun.forEach { $0() }
  58.728 +        }
  58.729 +        guard let vm = viewModel as? EmailDetailViewModel else {
  58.730 +            Log.shared.errorAndCrash("No VM")
  58.731 +            return
  58.732 +        }
  58.733 +        if vm.shouldScrollBackToCurrentlyViewdCellAfterUpdate {
  58.734 +            // Dis- and later enable animations while updating to avoid visible glitches while first
  58.735 +            // updating the colelction and then scroll back to the cell the user is currently viewing.
  58.736 +            UIView.setAnimationsEnabled(false)
  58.737 +            collectionView?.performBatchUpdates(performChangesBlock)
  58.738 +            UIView.setAnimationsEnabled(true)
  58.739 +            // ... and make sure the the previously shown message is still shown after the update.
  58.740 +            scrollToLastViewedCell()
  58.741 +        } else {
  58.742 +            collectionView?.performBatchUpdates(performChangesBlock)
  58.743 +        }
  58.744 +        configureView()
  58.745 +        guard let indexPath = indexPathOfCurrentlyVisibleCell else {
  58.746 +            // Empty list, is ok.
  58.747 +            // Do nothing.
  58.748 +            return
  58.749 +        }
  58.750 +        // Must be dispatched to avoid recursive saves
  58.751 +        // (save -> Queryresults Delegate -> calls us -> save -> ...)
  58.752 +        DispatchQueue.main.async {
  58.753 +            vm.handleEmailShown(forItemAt: indexPath)
  58.754 +        }
  58.755 +    }
  58.756 +
  58.757 +    func reloadData(viewModel: EmailDisplayViewModel) {
  58.758 +        collectionView?.reloadData()
  58.759 +        DispatchQueue.main.async { [weak self] in
  58.760 +            guard let me = self else {
  58.761 +                Log.shared.errorAndCrash("Lost myself")
  58.762 +                return
  58.763 +            }
  58.764 +            me.configureView()
  58.765 +        }
  58.766 +    }
  58.767 +
  58.768 +    func select(itemAt indexPath: IndexPath) {
  58.769 +        scroll(to: indexPath, animated: false)
  58.770 +        configureView()
  58.771 +    }
  58.772 +
  58.773 +    private func addUpdateTask(_ block: @escaping ()->Void) {
  58.774 +        collectionViewUpdateTasks.append(block)
  58.775 +    }
  58.776 +}
  58.777 +
  58.778 +// MARK: - EmailViewControllerDelegate
  58.779 +
  58.780 +extension EmailDetailViewController: EmailViewControllerDelegate {
  58.781 +
  58.782 +    func showPdfPreview(forPdfAt url: URL) {
  58.783 +        pdfPreviewUrl = url
  58.784 +        let previewController = QLPreviewController()
  58.785 +        previewController.dataSource = self
  58.786 +        present(previewController, animated: true, completion: nil)
  58.787 +    }
  58.788 +}
  58.789 +
  58.790 +// MARK: - QLPreviewControllerDataSource
  58.791 +
  58.792 +extension EmailDetailViewController: QLPreviewControllerDataSource {
  58.793 +
  58.794 +    func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
  58.795 +        return 1
  58.796 +    }
  58.797 +
  58.798 +    func previewController(_ controller: QLPreviewController,
  58.799 +                           previewItemAt index: Int) -> QLPreviewItem {
  58.800 +        guard let url = pdfPreviewUrl else {
  58.801 +            fatalError("Could not load URL")
  58.802 +        }
  58.803 +        return url as QLPreviewItem
  58.804 +    }
  58.805 +}
    59.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    59.2 +++ b/pEpForiOS/UI/EmailDisplay/EmailDetailView/EmailDetailViewModel.swift	Fri Feb 07 12:31:01 2020 +0100
    59.3 @@ -0,0 +1,281 @@
    59.4 +//
    59.5 +//  EmailDetailViewModel.swift
    59.6 +//  pEp
    59.7 +//
    59.8 +//  Created by Andreas Buff on 04.12.19.
    59.9 +//  Copyright © 2019 p≡p Security S.A. All rights reserved.
   59.10 +//
   59.11 +
   59.12 +import MessageModel
   59.13 +import PEPObjCAdapterFramework
   59.14 +
   59.15 +protocol EmailDetailViewModelDelegate: EmailDisplayViewModelDelegate {
   59.16 +
   59.17 +    /// `emailListViewModel(viewModel:didUpdateDataAt:)` should not reload the cell but update the
   59.18 +    /// flags and such.
   59.19 +    /// This callback is to handle the only case where the cell has to be reloaded: A mail is
   59.20 +    /// shown as undecryptable and has been decrypted while displaying it.
   59.21 +    /// - Parameter indexPath: indexpath of mail to reload
   59.22 +    func isNotUndecryptableAnyMore(indexPath: IndexPath)
   59.23 +}
   59.24 +
   59.25 +/// Reports back currently shown email changes.
   59.26 +protocol EmailDetailViewModelSelectionChangeDelegate: class {
   59.27 +    /// Called when the currently shown message changes
   59.28 +    func emailDetailViewModel(emailDetailViewModel: EmailDetailViewModel,
   59.29 +                              didSelectItemAt indexPath: IndexPath)
   59.30 +}
   59.31 +
   59.32 +class EmailDetailViewModel: EmailDisplayViewModel {
   59.33 +    /// Used to figure out whether or not the currently displayed message has been decrypted while
   59.34 +    /// being shown to the user.
   59.35 +    private var pathsForMessagesMarkedForRedecrypt = [IndexPath]()
   59.36 +    /// Remember the message the user is viewing
   59.37 +    private var lastShownMessage: Message?
   59.38 +    /// Whether or not a message has been inserted or removed before the currently shown message.
   59.39 +    /// Used to figure out if we need to scroll to the currently viewed message after update.
   59.40 +    private var updateInsertedOrRemovedMessagesBeforeCurrentlyShownMessage = false
   59.41 +
   59.42 +    weak var selectionChangeDelegate: EmailDetailViewModelSelectionChangeDelegate?
   59.43 +
   59.44 +    init(messageQueryResults: MessageQueryResults,
   59.45 +         delegate: EmailDisplayViewModelDelegate? = nil) {
   59.46 +        super.init(messageQueryResults: messageQueryResults)
   59.47 +        self.messageQueryResults.rowDelegate = self
   59.48 +    }
   59.49 +
   59.50 +    /// Replaces and uses the currently used message query with the given one. The displayed
   59.51 +    /// messages get updated automatically.
   59.52 +    /// - Parameter qrc: messages to display to the user
   59.53 +    public func replaceMessageQueryResults(with qrc: MessageQueryResults) throws {
   59.54 +        messageQueryResults = qrc
   59.55 +        messageQueryResults.rowDelegate = self
   59.56 +        try messageQueryResults.startMonitoring()
   59.57 +        reset()
   59.58 +        delegate?.reloadData(viewModel: self)
   59.59 +    }
   59.60 +
   59.61 +    /// Action handling
   59.62 +    /// - Parameter indexPath: indexPath of cell the flag button has been pressed for
   59.63 +    public func handleFlagButtonPress(for indexPath: IndexPath) {
   59.64 +        guard let message = message(representedByRowAt: indexPath) else {
   59.65 +            Log.shared.errorAndCrash("No msg")
   59.66 +            return
   59.67 +        }
   59.68 +        let flags = message.imapFlags
   59.69 +        flags.flagged = !flags.flagged
   59.70 +        message.imapFlags = flags
   59.71 +        Session.main.commit()
   59.72 +    }
   59.73 +
   59.74 +    /// Action handling
   59.75 +    /// - Parameter indexPath: indexPath of cell the destructive button has been pressed for
   59.76 +    public func handleDestructiveButtonPress(for indexPath: IndexPath) {
   59.77 +        guard let message = message(representedByRowAt: indexPath) else {
   59.78 +            Log.shared.errorAndCrash("No msg")
   59.79 +            return
   59.80 +        }
   59.81 +        delete(messages: [message])
   59.82 +    }
   59.83 +
   59.84 +    /// Must be called whenever a new message has been displayed.
   59.85 +    /// - Parameter indexPath: indexPath of the cell that has been displayed
   59.86 +    public func handleEmailShown(forItemAt indexPath: IndexPath) {
   59.87 +        lastShownMessage = message(representedByRowAt: indexPath)
   59.88 +        markForRedecryptionIfNeeded(messageRepresentedBy: indexPath)
   59.89 +        markSeenIfNeeded(messageRepresentedby: indexPath)
   59.90 +        selectionChangeDelegate?.emailDetailViewModel(emailDetailViewModel: self,
   59.91 +                                                      didSelectItemAt: indexPath)
   59.92 +    }
   59.93 +
   59.94 +    /// The indexpath of the last displayerd message.
   59.95 +    /// Used to scroll to after the data soure has been updated.
   59.96 +    /// Returns `nil` in case the previously shown message is not contained in the query results
   59.97 +    /// any more after updating the data source.
   59.98 +    public var indexPathForCellDisplayedBeforeUpdating: IndexPath? {
   59.99 +        guard
  59.100 +            let messageShownBeforeUpdating = lastShownMessage,
  59.101 +            !messageShownBeforeUpdating.isDeleted
  59.102 +            else {
  59.103 +                // Nothing to do
  59.104 +                return nil
  59.105 +        }
  59.106 +        for i in 0..<messageQueryResults.all.count {
  59.107 +            let testee = messageQueryResults[i]
  59.108 +            if testee == messageShownBeforeUpdating {
  59.109 +                return IndexPath(item: i, section: 0)
  59.110 +            }
  59.111 +        }
  59.112 +        return nil
  59.113 +    }
  59.114 +
  59.115 +    /// Scroll to `indexPathForCellDisplayedBeforeUpdating` after the collection has been updated
  59.116 +    /// (only) if this is true.
  59.117 +    public var shouldScrollBackToCurrentlyViewdCellAfterUpdate: Bool {
  59.118 +        return updateInsertedOrRemovedMessagesBeforeCurrentlyShownMessage
  59.119 +    }
  59.120 +
  59.121 +    /// - Parameter indexPath: indexPath of the cell to show the destructive button for.
  59.122 +    /// - returns: The icon to use for the destruktive button (delete, archive, ...)
  59.123 +    public func destructiveButtonIcon(forMessageAt indexPath: IndexPath?) -> UIImage? {
  59.124 +        guard
  59.125 +            let path = indexPath,
  59.126 +            let msg = message(representedByRowAt: path) else {
  59.127 +                Log.shared.info("Nothing shown")
  59.128 +                return nil
  59.129 +        }
  59.130 +        if msg.parent.defaultDestructiveActionIsArchive {
  59.131 +            return #imageLiteral(resourceName: "folders-icon-archive")
  59.132 +        } else {
  59.133 +            return #imageLiteral(resourceName: "folders-icon-trash")
  59.134 +        }
  59.135 +    }
  59.136 +
  59.137 +    /// - Parameter indexPath: indexPath of the cell to show the flagged state button for.
  59.138 +    /// - returns: The icon to use for the flagging button of cell at indexPath
  59.139 +    public func flagButtonIcon(forMessageAt indexPath: IndexPath?) -> UIImage? {
  59.140 +        guard
  59.141 +            let path = indexPath,
  59.142 +            let msg = message(representedByRowAt: path) else {
  59.143 +                Log.shared.info("Nothing shown")
  59.144 +                return nil
  59.145 +        }
  59.146 +        if msg.imapFlags.flagged {
  59.147 +            return #imageLiteral(resourceName: "icon-flagged")
  59.148 +        } else {
  59.149 +            return #imageLiteral(resourceName: "icon-unflagged")
  59.150 +        }
  59.151 +    }
  59.152 +
  59.153 +    /// - Parameter indexPath: indexPath of the cell to show the pEp rating for.
  59.154 +    /// - returns: pEp rating for cell at given indexPath
  59.155 +    public func pEpRating(forItemAt indexPath: IndexPath) -> PEPRating {
  59.156 +        guard let message = message(representedByRowAt: indexPath) else {
  59.157 +            Log.shared.errorAndCrash("No msg")
  59.158 +            return .undefined
  59.159 +        }
  59.160 +        return message.pEpRating()
  59.161 +    }
  59.162 +
  59.163 +    /// - Parameter indexPath: indexPath of the cell to compute result for.
  59.164 +    /// - returns:  Whether or not to show privacy icon for cell at given indexPath
  59.165 +    public func shouldShowPrivacyStatus(forItemAt indexPath: IndexPath) -> Bool {
  59.166 +        guard let message = message(representedByRowAt: indexPath) else {
  59.167 +            Log.shared.errorAndCrash("No msg")
  59.168 +            return false
  59.169 +        }
  59.170 +        let handshakeCombos = message.handshakeActionCombinations()
  59.171 +        guard !handshakeCombos.isEmpty else {
  59.172 +            return false
  59.173 +        }
  59.174 +        return true
  59.175 +    }
  59.176 +
  59.177 +    /// Destination VM Factory - Move To Folder VM
  59.178 +    /// - Parameter indexPath: indexPath of the cell to show "moveToFolder" view for.
  59.179 +    /// - returns:  MoveToAccountViewModel configured for message represented by the given indexPath
  59.180 +    public func getMoveToFolderViewModel(forMessageRepresentedByItemAt indexPath: IndexPath) -> MoveToAccountViewModel? {
  59.181 +        guard let msg = message(representedByRowAt: indexPath) else {
  59.182 +            Log.shared.errorAndCrash("Nothing to move?")
  59.183 +            return nil
  59.184 +        }
  59.185 +        return MoveToAccountViewModel(messages: [msg])
  59.186 +    }
  59.187 +}
  59.188 +
  59.189 +// MARK: - Private
  59.190 +
  59.191 +extension EmailDetailViewModel {
  59.192 +
  59.193 +    /// Resets bookholding vars
  59.194 +    private func reset() {
  59.195 +        pathsForMessagesMarkedForRedecrypt = [IndexPath]()
  59.196 +        lastShownMessage = nil
  59.197 +        updateInsertedOrRemovedMessagesBeforeCurrentlyShownMessage = false
  59.198 +    }
  59.199 +
  59.200 +    private func markSeenIfNeeded(messageRepresentedby indexPath: IndexPath) {
  59.201 +        guard let message = message(representedByRowAt: indexPath) else {
  59.202 +            Log.shared.errorAndCrash("No msg")
  59.203 +            return
  59.204 +        }
  59.205 +        message.markAsSeen()
  59.206 +    }
  59.207 +
  59.208 +    private func markForRedecryptionIfNeeded(messageRepresentedBy indexPath: IndexPath) {
  59.209 +        // rm previously stored IndexPath for this message.
  59.210 +        pathsForMessagesMarkedForRedecrypt = pathsForMessagesMarkedForRedecrypt.filter { $0 != indexPath }
  59.211 +        guard let message = message(representedByRowAt: indexPath) else {
  59.212 +            Log.shared.errorAndCrash("No msg")
  59.213 +            return
  59.214 +        }
  59.215 +        // The user may be about to view an yet undecrypted message.
  59.216 +        // If so, try again to decrypt it.
  59.217 +        if message.markForRetryDecryptIfUndecryptable() {
  59.218 +            pathsForMessagesMarkedForRedecrypt.append(indexPath)
  59.219 +        }
  59.220 +    }
  59.221 +
  59.222 +    private func isHandshakePossible(forItemAt indexPath: IndexPath) -> Bool {
  59.223 +        guard let message = message(representedByRowAt: indexPath) else {
  59.224 +            Log.shared.errorAndCrash("No msg")
  59.225 +            return false
  59.226 +        }
  59.227 +        let handshakeCombos = message.handshakeActionCombinations()
  59.228 +        guard !handshakeCombos.isEmpty else {
  59.229 +            return false
  59.230 +        }
  59.231 +        return true
  59.232 +    }
  59.233 +}
  59.234 +
  59.235 +// MARK: - QueryResultsIndexPathRowDelegate
  59.236 +
  59.237 +extension EmailDetailViewModel: QueryResultsIndexPathRowDelegate {
  59.238 +
  59.239 +    func didInsertRow(indexPath: IndexPath) {
  59.240 +        handleIndexPathIsBeforeCurrentlyShownMessage(insertedIndexPath: indexPath)
  59.241 +        delegate?.emailListViewModel(viewModel: self, didInsertDataAt: [indexPath])
  59.242 +    }
  59.243 +
  59.244 +    func didUpdateRow(indexPath: IndexPath) {
  59.245 +        if pathsForMessagesMarkedForRedecrypt.contains(indexPath) {
  59.246 +            if let message = message(representedByRowAt: indexPath),
  59.247 +                !message.pEpRating().isUnDecryptable() {
  59.248 +                guard let delegate = delegate as? EmailDetailViewModelDelegate else {
  59.249 +                    Log.shared.errorAndCrash("Inbvalid state")
  59.250 +                    return
  59.251 +                }
  59.252 +                // Previously undecryptable message has successfully been decrypted.
  59.253 +                delegate.isNotUndecryptableAnyMore(indexPath: indexPath)
  59.254 +            }
  59.255 +            pathsForMessagesMarkedForRedecrypt = pathsForMessagesMarkedForRedecrypt.filter { $0 != indexPath }
  59.256 +        }
  59.257 +        delegate?.emailListViewModel(viewModel: self, didUpdateDataAt: [indexPath])
  59.258 +    }
  59.259 +
  59.260 +    func didDeleteRow(indexPath: IndexPath) {
  59.261 +        handleIndexPathIsBeforeCurrentlyShownMessage(insertedIndexPath: indexPath)
  59.262 +        delegate?.emailListViewModel(viewModel: self, didRemoveDataAt: [indexPath])
  59.263 +    }
  59.264 +
  59.265 +    func didMoveRow(from: IndexPath, to: IndexPath) {
  59.266 +        delegate?.emailListViewModel(viewModel: self, didMoveData: from, toIndexPath: to)
  59.267 +    }
  59.268 +
  59.269 +    func willChangeResults() {
  59.270 +        updateInsertedOrRemovedMessagesBeforeCurrentlyShownMessage = false
  59.271 +        delegate?.willReceiveUpdates(viewModel: self)
  59.272 +    }
  59.273 +
  59.274 +    func didChangeResults() {
  59.275 +        delegate?.allUpdatesReceived(viewModel: self)
  59.276 +    }
  59.277 +
  59.278 +    private func handleIndexPathIsBeforeCurrentlyShownMessage(insertedIndexPath: IndexPath) {
  59.279 +        if let currentlyShownIndex = indexPathForCellDisplayedBeforeUpdating,
  59.280 +            insertedIndexPath.row <= currentlyShownIndex.row {
  59.281 +            updateInsertedOrRemovedMessagesBeforeCurrentlyShownMessage = true
  59.282 +        }
  59.283 +    }
  59.284 +}
    60.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    60.2 +++ b/pEpForiOS/UI/EmailDisplay/EmailDisplayList/EmailListViewCell.swift	Fri Feb 07 12:31:01 2020 +0100
    60.3 @@ -0,0 +1,260 @@
    60.4 +//
    60.5 +//  EmailListViewCell.swift
    60.6 +//  pEpForiOS
    60.7 +//
    60.8 +//  Created by Dirk Zimmermann on 16/04/16.
    60.9 +//  Copyright © 2016 p≡p Security S.A. All rights reserved.
   60.10 +//
   60.11 +
   60.12 +import UIKit
   60.13 +import MessageModel
   60.14 +import SwipeCellKit
   60.15 +
   60.16 +class EmailListViewCell: PEPSwipeTableViewCell, MessageViewModelConfigurable {
   60.17 +    public static let storyboardId = "EmailListViewCell"
   60.18 +
   60.19 +    @IBOutlet weak var addressLabel: UILabel!
   60.20 +    @IBOutlet weak var subjectLabel: UILabel!
   60.21 +    @IBOutlet weak var summaryLabel: UILabel!
   60.22 +    @IBOutlet weak var dateLabel: UILabel!
   60.23 +
   60.24 +    @IBOutlet weak var flaggedImageView: UIImageView!
   60.25 +
   60.26 +    @IBOutlet weak var ratingImage: UIImageView!
   60.27 +    @IBOutlet weak var attachmentIcon: UIImageView!
   60.28 +    @IBOutlet weak var contactImageView: UIImageView!
   60.29 +
   60.30 +    /**
   60.31 +     Fake constraint for IB to be happy.
   60.32 +     - Note: This gets deactivated on runtime.
   60.33 +     */
   60.34 +    @IBOutlet weak var fakeRatingImageToContactImageVertical: NSLayoutConstraint?
   60.35 +
   60.36 +    /**
   60.37 +     Fake constraint for IB to be happy.
   60.38 +     - Note: This gets deactivated on runtime.
   60.39 +     */
   60.40 +    @IBOutlet weak var fakeRatingImageToContactImageHorizontal: NSLayoutConstraint?
   60.41 +
   60.42 +    private var viewModel: MessageViewModel?
   60.43 +
   60.44 +    /**
   60.45 +     Original selection background color
   60.46 +     - Note: When a cell is selected in edit mode the background color must be the same as
   60.47 +     unselected.
   60.48 +     For that reason we need to store the original selected background color to avoid loosing it
   60.49 +     if we need it in the future.
   60.50 +     */
   60.51 +    private var originalBackgroundSelectionColor: UIColor?
   60.52 +
   60.53 +    private var hasAttachment:Bool = false {
   60.54 +        didSet {
   60.55 +            if hasAttachment {
   60.56 +                attachmentIcon.isHidden = false
   60.57 +            } else {
   60.58 +                attachmentIcon.isHidden = true
   60.59 +            }
   60.60 +        }
   60.61 +    }
   60.62 +
   60.63 +    public var isFlagged:Bool = false {
   60.64 +        didSet {
   60.65 +            if isFlagged {
   60.66 +                setFlagged()
   60.67 +            } else {
   60.68 +                unsetFlagged()
   60.69 +            }
   60.70 +        }
   60.71 +    }
   60.72 +
   60.73 +    public var isSeen:Bool = false {
   60.74 +        didSet {
   60.75 +            if isSeen {
   60.76 +                setSeen()
   60.77 +            } else {
   60.78 +                unsetSeen()
   60.79 +            }
   60.80 +        }
   60.81 +    }
   60.82 +
   60.83 +    // MARK: - View overrides (life cycle etc.)
   60.84 +
   60.85 +    override func awakeFromNib() {
   60.86 +        super.awakeFromNib()
   60.87 +        originalBackgroundSelectionColor = selectedBackgroundView?.backgroundColor
   60.88 +        contactImageView.applyContactImageCornerRadius()
   60.89 +        resetToDefault()
   60.90 +    }
   60.91 +
   60.92 +    override func prepareForReuse() {
   60.93 +        super.prepareForReuse()
   60.94 +        clear()
   60.95 +        resetToDefault()
   60.96 +    }
   60.97 +
   60.98 +    override func layoutSubviews() {
   60.99 +        super.layoutSubviews()
  60.100 +
  60.101 +        if let constr = fakeRatingImageToContactImageVertical {
  60.102 +            constr.isActive = false
  60.103 +        }
  60.104 +        if let constr = fakeRatingImageToContactImageHorizontal {
  60.105 +            constr.isActive = false
  60.106 +        }
  60.107 +
  60.108 +        ratingImage.centerXAnchor.constraint(
  60.109 +            equalTo: contactImageView.rightAnchor).isActive = true
  60.110 +        ratingImage.centerYAnchor.constraint(
  60.111 +            equalTo: contactImageView.bottomAnchor).isActive = true
  60.112 +    }
  60.113 +
  60.114 +    public func configure(for viewModel: MessageViewModel) {
  60.115 +        self.viewModel = viewModel
  60.116 +
  60.117 +        // Occupy space in any case. Otherwise the summary might be filled
  60.118 +        // _after_ this function has ended and the cell has already been
  60.119 +        // layouted, leading to a smaller cell than usual.
  60.120 +        summaryLabel.text = " "
  60.121 +
  60.122 +        addressLabel.text = atLeastOneSpace(possiblyEmptyString: viewModel.displayedUsername)
  60.123 +        subjectLabel.text = atLeastOneSpace(possiblyEmptyString: viewModel.subject)
  60.124 +
  60.125 +        viewModel.bodyPeekCompletion = { [weak self] bodyPeek in
  60.126 +            self?.summaryLabel.text = bodyPeek == "" ? " " : bodyPeek
  60.127 +        }
  60.128 +
  60.129 +        isFlagged = viewModel.isFlagged
  60.130 +        isSeen = viewModel.isSeen
  60.131 +
  60.132 +        hasAttachment = viewModel.showAttchmentIcon
  60.133 +        dateLabel.text = viewModel.dateText
  60.134 +
  60.135 +        // Message threading is not supported. Let's keep it for now. It might be helpful for
  60.136 +        // reimplementing.
  60.137 +        //        configureThreadIndicator(for: viewModel)
  60.138 +
  60.139 +        if viewModel.senderContactImage != nil {
  60.140 +            setContactImage(image: viewModel.senderContactImage)
  60.141 +        } else {
  60.142 +            viewModel.getProfilePicture { [weak self] image in
  60.143 +                DispatchQueue.main.async {
  60.144 +                    self?.setContactImage(image: image)
  60.145 +                }
  60.146 +            }
  60.147 +        }
  60.148 +        setPepRatingImage(image: viewModel.getSecurityBadge())
  60.149 +    }
  60.150 +
  60.151 +    public func clear() {
  60.152 +        viewModel?.unsubscribeForUpdates()
  60.153 +        viewModel = nil
  60.154 +    }
  60.155 +}
  60.156 +
  60.157 +// MARK: - Private
  60.158 +
  60.159 +extension EmailListViewCell {
  60.160 +
  60.161 +    private static var flaggedImage: UIImage? = nil
  60.162 +    private static var emptyContactImage = UIImage(named: "empty-avatar")
  60.163 +
  60.164 +    // Message threading is not supported. Let's keep it for now. It might be helpful for
  60.165 +    // reimplementing.
  60.166 +    //    private func configureThreadIndicator(for viewModel: MessageViewModel) {
  60.167 +    //        guard let _ = messageCountLabel,
  60.168 +    //            let _ = threadIndicator else {
  60.169 +    //                messageCount = 0
  60.170 +    //                return
  60.171 +    //        }
  60.172 +    //        viewModel.messageCount { (messageCount) in
  60.173 +    //            self.messageCount = messageCount
  60.174 +    //        }
  60.175 +    //
  60.176 +    //    }
  60.177 +
  60.178 +    private func setPepRatingImage(image: UIImage?) {
  60.179 +        if ratingImage.image != image {
  60.180 +            self.ratingImage.image = image
  60.181 +            self.ratingImage.isHidden = (image == nil)
  60.182 +        }
  60.183 +    }
  60.184 +
  60.185 +    private func setContactImage(image: UIImage?) {
  60.186 +        guard image != nil else {
  60.187 +            return
  60.188 +        }
  60.189 +        self.contactImageView.image = image
  60.190 +    }
  60.191 +
  60.192 +    private func resetToDefault() {
  60.193 +        viewModel?.unsubscribeForUpdates()
  60.194 +        viewModel = nil
  60.195 +        summaryLabel.text = nil
  60.196 +        ratingImage.isHidden = true
  60.197 +        ratingImage.image = nil
  60.198 +        contactImageView.image = EmailListViewCell.emptyContactImage
  60.199 +        tintColor = UIColor.pEpGreen
  60.200 +    }
  60.201 +
  60.202 +    private func setFlagged() {
  60.203 +        flaggedImageView.isHidden = false
  60.204 +        flaggedImageView.image = UIImage(named: "icon-flagged")
  60.205 +    }
  60.206 +
  60.207 +    private func unsetFlagged() {
  60.208 +        flaggedImageView.isHidden = true
  60.209 +    }
  60.210 +
  60.211 +    private func setSeen() {
  60.212 +        if let font = addressLabel.font {
  60.213 +            let seenFont = UIFont.systemFont(ofSize: font.pointSize)
  60.214 +            if font != seenFont {
  60.215 +                setupLabels(font: seenFont)
  60.216 +            }
  60.217 +        }
  60.218 +    }
  60.219 +
  60.220 +    private func unsetSeen() {
  60.221 +        if let font = addressLabel.font {
  60.222 +            let font = UIFont.boldSystemFont(ofSize: font.pointSize)
  60.223 +            setupLabels(font: font)
  60.224 +        }
  60.225 +    }
  60.226 +
  60.227 +    private func setupLabels(font: UIFont) {
  60.228 +        addressLabel.font = font
  60.229 +        subjectLabel.font = font
  60.230 +        summaryLabel.font = font
  60.231 +        dateLabel.font = font
  60.232 +    }
  60.233 +
  60.234 +
  60.235 +    /// This method highlights the cell that is being pressed.
  60.236 +    /// - Note: We only accept this if the cell is not in edit mode.
  60.237 +    override func setHighlighted(_ highlighted: Bool, animated: Bool) {
  60.238 +        if !isEditing {
  60.239 +            super.setHighlighted(highlighted, animated: animated)
  60.240 +        }
  60.241 +    }
  60.242 +
  60.243 +    override func setSelected(_ selected: Bool, animated: Bool) {
  60.244 +        super.setSelected(selected, animated: false)
  60.245 +        let viewForHighlight = UIView()
  60.246 +        self.selectedBackgroundView = viewForHighlight
  60.247 +        if self.isEditing {
  60.248 +            viewForHighlight.backgroundColor = UIColor.clear
  60.249 +        } else {
  60.250 +            viewForHighlight.backgroundColor = originalBackgroundSelectionColor
  60.251 +        }
  60.252 +    }
  60.253 +
  60.254 +    /// - Returns: " " (a space) instead of an empty String, otherwise the original String
  60.255 +    /// unchanged.
  60.256 +    private func atLeastOneSpace(possiblyEmptyString: String) -> String {
  60.257 +        if possiblyEmptyString == "" {
  60.258 +            return " "
  60.259 +        } else {
  60.260 +            return possiblyEmptyString
  60.261 +        }
  60.262 +    }
  60.263 +}
    61.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    61.2 +++ b/pEpForiOS/UI/EmailDisplay/EmailDisplayList/EmailListViewController.swift	Fri Feb 07 12:31:01 2020 +0100
    61.3 @@ -0,0 +1,1370 @@
    61.4 +//
    61.5 +//  EmailListViewController.swift
    61.6 +//  pEpForiOS
    61.7 +//
    61.8 +//  Created by Dirk Zimmermann on 16/04/16.
    61.9 +//  Copyright © 2016 p≡p Security S.A. All rights reserved.
   61.10 +//
   61.11 +
   61.12 +import UIKit
   61.13 +
   61.14 +import SwipeCellKit
   61.15 +import pEpIOSToolbox
   61.16 +
   61.17 +class EmailListViewController: BaseViewController, SwipeTableViewCellDelegate {
   61.18 +    /// Stuff that must be done once only in viewWillAppear
   61.19 +    private var doOnce: (()-> Void)?
   61.20 +    /// With this tag we recognize the pEp button item, for easy removal later.
   61.21 +    private let pEpButtonItemTag = 7
   61.22 +    /// With this tag we recognize our own created flexible space buttons, for easy removal later.
   61.23 +    private let flexibleSpaceButtonItemTag = 77
   61.24 +    /// True if the pEp button on the left/master side should be shown.
   61.25 +    private var shouldShowPepButtonInMasterToolbar = true
   61.26 +    /// The key path for observing the view controllers of the split view controller,
   61.27 +    /// compatible with Objective-C.
   61.28 +    private let splitViewObserverKeyPath = #keyPath(UISplitViewController.viewControllers)
   61.29 +    /// With KVO we have to keep our books lest not to remove an observer without
   61.30 +    /// observing first.
   61.31 +    private var observingSplitViewControllers = false
   61.32 +
   61.33 +    public static let storyboardId = "EmailListViewController"
   61.34 +    public static let storyboardNavigationControllerId = "EmailListNavigationViewController"
   61.35 +    static let FILTER_TITLE_MAX_XAR = 20
   61.36 +
   61.37 +    @IBOutlet weak var enableFilterButton: UIBarButtonItem!
   61.38 +    @IBOutlet weak var tableView: UITableView!
   61.39 +
   61.40 +    var viewModel: EmailListViewModel? {
   61.41 +        didSet {
   61.42 +            viewModel?.delegate = self
   61.43 +        }
   61.44 +    }
   61.45 +
   61.46 +    /// This is used to handle the selection row when it recives an update
   61.47 +    /// and also when swipeCellAction is performed to store from which cell the action is done.
   61.48 +    private var lastSelectedIndexPath: IndexPath?
   61.49 +
   61.50 +    private let searchController = UISearchController(searchResultsController: nil)
   61.51 +
   61.52 +    //swipe acctions types
   61.53 +    var buttonDisplayMode: ButtonDisplayMode = .titleAndImage
   61.54 +    var buttonStyle: ButtonStyle = .backgroundColor
   61.55 +
   61.56 +    private var swipeDelete: SwipeAction? = nil
   61.57 +
   61.58 +    private let refreshController = UIRefreshControl()
   61.59 +
   61.60 +    var textFilterButton: UIBarButtonItem = UIBarButtonItem(title: "",
   61.61 +                                                            style: .plain,
   61.62 +                                                            target: nil,
   61.63 +                                                            action: nil)
   61.64 +
   61.65 +    // MARK: - Life Cycle
   61.66 +
   61.67 +    override func viewDidLoad() {
   61.68 +        super.viewDidLoad()
   61.69 +        doOnce = { [weak self] in
   61.70 +            guard let me = self else {
   61.71 +                Log.shared.errorAndCrash("Lost myself")
   61.72 +                return
   61.73 +            }
   61.74 +            guard let vm = me.viewModel else {
   61.75 +                Log.shared.errorAndCrash("No VM")
   61.76 +                return
   61.77 +            }
   61.78 +
   61.79 +            me.showNoMessageSelected()
   61.80 +
   61.81 +            me.updateFilterButtonView()
   61.82 +            vm.startMonitoring() //!!!: UI should not know about startMonitoring
   61.83 +            me.tableView.reloadData()
   61.84 +
   61.85 +            me.checkSplitViewState()
   61.86 +            me.watchDetailView()
   61.87 +            me.doOnce = nil
   61.88 +        }
   61.89 +        setup()
   61.90 +    }
   61.91 +
   61.92 +    override func viewWillAppear(_ animated: Bool) {
   61.93 +        super.viewWillAppear(animated)
   61.94 +        navigationController?.setToolbarHidden(false, animated: true)
   61.95 +        if MiscUtil.isUnitTest() {
   61.96 +            return
   61.97 +        }
   61.98 +
   61.99 +        lastSelectedIndexPath = nil
  61.100 +
  61.101 +        guard let vm = viewModel else {
  61.102 +            Log.shared.errorAndCrash("No VM.")
  61.103 +            return
  61.104 +        }
  61.105 +
  61.106 +        if !vm.showLoginView {
  61.107 +            doOnce?()
  61.108 +        }
  61.109 +
  61.110 +        setUpTextFilter()
  61.111 +    }
  61.112 +
  61.113 +    override func viewWillDisappear(_ animated: Bool) {
  61.114 +        super.viewWillAppear(animated)
  61.115 +        unwatchDetailView()
  61.116 +    }
  61.117 +
  61.118 +    deinit {
  61.119 +        NotificationCenter.default.removeObserver(self)
  61.120 +    }
  61.121 +
  61.122 +    // MARK: - Setup
  61.123 +
  61.124 +    private func setup() {
  61.125 +        tableView.delegate = self
  61.126 +        tableView.dataSource = self
  61.127 +        // rm seperator lines for empty view/cells
  61.128 +        tableView.tableFooterView = UIView()
  61.129 +        tableView.allowsMultipleSelectionDuringEditing = true
  61.130 +        setupSearchBar()
  61.131 +
  61.132 +        guard let vm = viewModel else {
  61.133 +            Log.shared.errorAndCrash("No VM")
  61.134 +            return
  61.135 +        }
  61.136 +
  61.137 +        if vm.showLoginView {
  61.138 +            showLoginScreen()
  61.139 +            return
  61.140 +        }
  61.141 +
  61.142 +        if vm.shouldShowTutorialWizard {
  61.143 +            TutorialWizardViewController.presentTutorialWizard(viewController: self)
  61.144 +            vm.didShowTutorialWizard()
  61.145 +        }
  61.146 +
  61.147 +        ///if we are in setup and the folder is unifiedInbox
  61.148 +        ///we have to reload the unifiedInbox to ensure that all the accounts are present.
  61.149 +        if vm.folderToShow is UnifiedInbox {
  61.150 +            viewModel = EmailListViewModel(delegate: self,
  61.151 +                                           folderToShow: UnifiedInbox())
  61.152 +        }
  61.153 +        setupRefreshControl()
  61.154 +
  61.155 +        title = viewModel?.folderName
  61.156 +        navigationController?.title = title
  61.157 +
  61.158 +        let flexibleSpace = createFlexibleBarButtonItem()
  61.159 +        toolbarItems?.append(contentsOf: [flexibleSpace, createPepBarButtonItem()])
  61.160 +    }
  61.161 +
  61.162 +    private func setupRefreshControl() {
  61.163 +        refreshController.tintColor = UIColor.pEpGreen
  61.164 +        refreshController.addTarget(self, action: #selector(refreshView(_:)), for: .valueChanged)
  61.165 +        // Apples default UIRefreshControl implementation is buggy when using a UITableView in a
  61.166 +        // UIViewController (instead of a UITableViewController). The UI freaks out while
  61.167 +        // refreshing and after refreshing the UI is messed (refreshControl and search bar above
  61.168 +        // first tableView cell. Adding the refreshControl as subview of UITableView works around
  61.169 +        // this issue without changing the NavigationBar's "show/hide SearchField when scrolling"
  61.170 +        // behaviour. Do NOT use the intended (`tableView.refreshControl`) way to set the refresh
  61.171 +        // controll up! = refreshController
  61.172 +         tableView.addSubview(refreshController)
  61.173 +    }
  61.174 +
  61.175 +    private func setUpTextFilter() {
  61.176 +        textFilterButton.isEnabled = false
  61.177 +        textFilterButton.action = #selector(showFilterOptions(_:))
  61.178 +        textFilterButton.target = self
  61.179 +
  61.180 +        let fontSize:CGFloat = 10;
  61.181 +        let font:UIFont = UIFont.boldSystemFont(ofSize: fontSize);
  61.182 +        let attributes = [NSAttributedString.Key.font: font];
  61.183 +
  61.184 +        textFilterButton.setTitleTextAttributes(attributes, for: UIControl.State.normal)
  61.185 +    }
  61.186 +
  61.187 +    // MARK: - Search Bar
  61.188 +
  61.189 +    private func setupSearchBar() {
  61.190 +        definesPresentationContext = true
  61.191 +        configureSearchBar()
  61.192 +        if #available(iOS 11.0, *) {
  61.193 +            searchController.isActive = false
  61.194 +            navigationItem.searchController = searchController
  61.195 +            navigationItem.hidesSearchBarWhenScrolling = true
  61.196 +        } else {
  61.197 +            addSearchBar10()
  61.198 +
  61.199 +            if tableView.tableHeaderView == nil {
  61.200 +                tableView.tableHeaderView = searchController.searchBar
  61.201 +            }
  61.202 +
  61.203 +            // some notifications to control when the app enter and recover from background
  61.204 +            NotificationCenter.default.addObserver(
  61.205 +                self,
  61.206 +                selector: #selector(didBecomeActiveInstallSearchBar10),
  61.207 +                name: UIApplication.didBecomeActiveNotification,
  61.208 +                object: nil)
  61.209 +            NotificationCenter.default.addObserver(
  61.210 +                self,
  61.211 +                selector: #selector(didBecomeInactiveUninstallSearchbar10),
  61.212 +                name: UIApplication.didEnterBackgroundNotification,
  61.213 +                object: nil)
  61.214 +        }
  61.215 +    }
  61.216 +
  61.217 +    /// Called on pull-to-refresh triggered
  61.218 +    @objc private func refreshView(_ sender: Any) {
  61.219 +        viewModel?.fetchNewMessages() {[weak self] in
  61.220 +            guard let me = self else {
  61.221 +                // Loosing self is a valid case here. The view might have been dismissed.
  61.222 +                return
  61.223 +            }
  61.224 +            // Loosing self is a valid use case here. We might have been dismissed.
  61.225 +            DispatchQueue.main.async {
  61.226 +                // We intentionally do NOT use me.tableView.refreshControl?.endRefreshing() here.
  61.227 +                // See comments in `setupRefreshControl` for details.
  61.228 +                me.refreshController.endRefreshing()
  61.229 +            }
  61.230 +        }
  61.231 +    }
  61.232 +
  61.233 +    /**
  61.234 +     Configure the search controller, shared between iOS versions 11 and earlier.
  61.235 +     */
  61.236 +    private func configureSearchBar() {
  61.237 +        searchController.searchResultsUpdater = self
  61.238 +        searchController.dimsBackgroundDuringPresentation = false
  61.239 +        searchController.delegate = self
  61.240 +    }
  61.241 +
  61.242 +    /**
  61.243 +     Showing the search controller in versions iOS 10 and earlier.
  61.244 +     */
  61.245 +    @objc func didBecomeActiveInstallSearchBar10() {
  61.246 +        if tableView.tableHeaderView == nil {
  61.247 +            tableView.tableHeaderView = searchController.searchBar
  61.248 +        }
  61.249 +    }
  61.250 +
  61.251 +    /**
  61.252 +     Hide/remove the search controller in versions iOS 10 and earlier.
  61.253 +     */
  61.254 +    @objc func didBecomeInactiveUninstallSearchbar10() {
  61.255 +        tableView.tableHeaderView = nil
  61.256 +    }
  61.257 +
  61.258 +    /**
  61.259 +     Add the search bar when running on iOS 10 or earlier.
  61.260 +     */
  61.261 +    private func addSearchBar10() {
  61.262 +        tableView.tableHeaderView = searchController.searchBar
  61.263 +        tableView.setContentOffset(CGPoint(x: 0.0,
  61.264 +                                           y: searchController.searchBar.frame.size.height),
  61.265 +                                   animated: false)
  61.266 +    }
  61.267 +
  61.268 +    // MARK: - Other
  61.269 +
  61.270 +    private func showEditDraftComposeView() {
  61.271 +        performSegue(withIdentifier: SegueIdentifier.segueEditDraft, sender: self)
  61.272 +    }
  61.273 +
  61.274 +    /// we have to handle the ipad/iphone segue in a different way. see IOS-1737
  61.275 +    private func showEmail(forCellAt indexPath: IndexPath) {
  61.276 +        if onlySplitViewMasterIsShown {
  61.277 +            performSegue(withIdentifier: SegueIdentifier.segueShowEmailNotSplitView, sender: self)
  61.278 +        } else {
  61.279 +            performSegue(withIdentifier: SegueIdentifier.segueShowEmailSplitView, sender: self)
  61.280 +        }
  61.281 +    }
  61.282 +
  61.283 +    private func showNoMessageSelected() {
  61.284 +        showEmptyDetailViewIfApplicable(message: NSLocalizedString(
  61.285 +            "Please choose a message",
  61.286 +            comment: "No messages has been selected for detail view"))
  61.287 +    }
  61.288 +
  61.289 +    private func showLoginScreen() {
  61.290 +        performSegue(withIdentifier:.segueAddNewAccount, sender: self)
  61.291 +        return
  61.292 +    }
  61.293 +
  61.294 +    // MARK: - Action Edit Button
  61.295 +
  61.296 +    private var tempToolbarItems: [UIBarButtonItem]?
  61.297 +    private var editRightButton: UIBarButtonItem?
  61.298 +    private var flagToolbarButton: UIBarButtonItem?
  61.299 +    private var unflagToolbarButton: UIBarButtonItem?
  61.300 +    private var readToolbarButton: UIBarButtonItem?
  61.301 +    private var unreadToolbarButton: UIBarButtonItem?
  61.302 +    private var deleteToolbarButton: UIBarButtonItem?
  61.303 +    private var moveToolbarButton: UIBarButtonItem?
  61.304 +
  61.305 +    private func showEditToolbar() {
  61.306 +
  61.307 +        tempToolbarItems = toolbarItems
  61.308 +
  61.309 +        // Flexible Space separation between the buttons
  61.310 +        let flexibleSpace = createFlexibleBarButtonItem()
  61.311 +
  61.312 +        var img = UIImage(named: "icon-flagged")
  61.313 +
  61.314 +        flagToolbarButton = UIBarButtonItem(image: img,
  61.315 +                                            style: UIBarButtonItem.Style.plain,
  61.316 +                                            target: self,
  61.317 +                                            action: #selector(flagToolbar(_:)))
  61.318 +        flagToolbarButton?.isEnabled = false
  61.319 +
  61.320 +        img = UIImage(named: "icon-unflagged")
  61.321 +
  61.322 +        unflagToolbarButton = UIBarButtonItem(image: img,
  61.323 +                                              style: UIBarButtonItem.Style.plain,
  61.324 +                                              target: self,
  61.325 +                                              action: #selector(unflagToolbar(_:)))
  61.326 +        unflagToolbarButton?.isEnabled = false
  61.327 +
  61.328 +        img = UIImage(named: "icon-read")
  61.329 +
  61.330 +        readToolbarButton = UIBarButtonItem(image: img,
  61.331 +                                            style: UIBarButtonItem.Style.plain,
  61.332 +                                            target: self,
  61.333 +                                            action: #selector(readToolbar(_:)))
  61.334 +        readToolbarButton?.isEnabled = false
  61.335 +
  61.336 +        img = UIImage(named: "icon-unread")
  61.337 +
  61.338 +        unreadToolbarButton = UIBarButtonItem(image: img,
  61.339 +                                              style: UIBarButtonItem.Style.plain,
  61.340 +                                              target: self,
  61.341 +                                              action: #selector(unreadToolbar(_:)))
  61.342 +        unreadToolbarButton?.isEnabled = false
  61.343 +
  61.344 +        img = UIImage(named: "folders-icon-trash")
  61.345 +
  61.346 +        deleteToolbarButton = UIBarButtonItem(image: img,
  61.347 +                                              style: UIBarButtonItem.Style.plain,
  61.348 +                                              target: self,
  61.349 +                                              action: #selector(deleteToolbar(_:)))
  61.350 +
  61.351 +        deleteToolbarButton?.isEnabled = false
  61.352 +
  61.353 +        img = UIImage(named: "swipe-archive")
  61.354 +
  61.355 +        moveToolbarButton = UIBarButtonItem(image: img,
  61.356 +                                            style: UIBarButtonItem.Style.plain,
  61.357 +                                            target: self,
  61.358 +                                            action: #selector(moveToolbar(_:)))
  61.359 +
  61.360 +        moveToolbarButton?.isEnabled = false
  61.361 +
  61.362 +        if var newToolbarItems = [flagToolbarButton, flexibleSpace, readToolbarButton,
  61.363 +                                  flexibleSpace, deleteToolbarButton, flexibleSpace,
  61.364 +                                  moveToolbarButton, flexibleSpace] as? [UIBarButtonItem] {
  61.365 +            if shouldShowPepButtonInMasterToolbar {
  61.366 +                newToolbarItems.append(createPepBarButtonItem())
  61.367 +            }
  61.368 +            toolbarItems = newToolbarItems
  61.369 +        }
  61.370 +
  61.371 +
  61.372 +        //right navigation button to ensure the logic
  61.373 +        let cancel = UIBarButtonItem(title: "Cancel",
  61.374 +                                     style: UIBarButtonItem.Style.plain,
  61.375 +                                     target: self,
  61.376 +                                     action: #selector(cancelToolbar(_:)))
  61.377 +
  61.378 +        editRightButton = navigationItem.rightBarButtonItem
  61.379 +        navigationItem.rightBarButtonItem = cancel
  61.380 +
  61.381 +    }
  61.382 +
  61.383 +    @objc private func showSettingsViewController() {
  61.384 +        UIUtils.presentSettings(on: self, appConfig: appConfig)
  61.385 +    }
  61.386 +
  61.387 +    @IBAction func editButtonPressed(_ sender: UIBarButtonItem) {
  61.388 +        showEditToolbar()
  61.389 +        tableView.setEditing(true, animated: true)
  61.390 +    }
  61.391 +
  61.392 +    @IBAction func showFilterOptions(_ sender: UIBarButtonItem!) {
  61.393 +        performSegue(withIdentifier: .segueShowFilter, sender: self)
  61.394 +    }
  61.395 +
  61.396 +    @IBAction func cancelToolbar(_ sender:UIBarButtonItem!) {
  61.397 +        showStandardToolbar()
  61.398 +        lastSelectedIndexPath = nil
  61.399 +        tableView.setEditing(false, animated: true)
  61.400 +    }
  61.401 +
  61.402 +    @IBAction func flagToolbar(_ sender:UIBarButtonItem!) {
  61.403 +        if let selectedItems = tableView.indexPathsForSelectedRows {
  61.404 +            viewModel?.markAsFlagged(indexPaths: selectedItems)
  61.405 +            selectedItems.forEach { (ip) in
  61.406 +                if let cell = self.tableView.cellForRow(at: ip) as? EmailListViewCell {
  61.407 +                    cell.isFlagged = true
  61.408 +                }
  61.409 +            }
  61.410 +        }
  61.411 +        cancelToolbar(sender)
  61.412 +    }
  61.413 +
  61.414 +    @IBAction func unflagToolbar(_ sender:UIBarButtonItem!) {
  61.415 +        if let selectedItems = tableView.indexPathsForSelectedRows {
  61.416 +            viewModel?.markAsUnFlagged(indexPaths: selectedItems)
  61.417 +            selectedItems.forEach { (ip) in
  61.418 +                if let cell = self.tableView.cellForRow(at: ip) as? EmailListViewCell {
  61.419 +                    cell.isFlagged = false
  61.420 +                }
  61.421 +            }
  61.422 +        }
  61.423 +        cancelToolbar(sender)
  61.424 +    }
  61.425 +
  61.426 +    @IBAction func readToolbar(_ sender:UIBarButtonItem!) {
  61.427 +        if let selectedItems = tableView.indexPathsForSelectedRows {
  61.428 +            selectedItems.forEach { (ip) in
  61.429 +                if let cell = self.tableView.cellForRow(at: ip) as? EmailListViewCell {
  61.430 +                    cell.isSeen = true
  61.431 +                }
  61.432 +            }
  61.433 +            viewModel?.markAsRead(indexPaths: selectedItems)
  61.434 +        }
  61.435 +        cancelToolbar(sender)
  61.436 +    }
  61.437 +
  61.438 +    @IBAction func unreadToolbar(_ sender:UIBarButtonItem!) {
  61.439 +        if let selectedItems = tableView.indexPathsForSelectedRows {
  61.440 +            viewModel?.markAsUnread(indexPaths: selectedItems)
  61.441 +            selectedItems.forEach { (ip) in
  61.442 +                if let cell = self.tableView.cellForRow(at: ip) as? EmailListViewCell {
  61.443 +                    cell.isSeen = false
  61.444 +                }
  61.445 +            }
  61.446 +        }
  61.447 +        cancelToolbar(sender)
  61.448 +    }
  61.449 +
  61.450 +    @IBAction func moveToolbar(_ sender:UIBarButtonItem!) {
  61.451 +        performSegue(withIdentifier: .segueShowMoveToFolder, sender: self)
  61.452 +        cancelToolbar(sender)
  61.453 +    }
  61.454 +
  61.455 +    @IBAction func deleteToolbar(_ sender:UIBarButtonItem!) {
  61.456 +        if let vm = viewModel,
  61.457 +            let selectedIndexPaths = tableView.indexPathsForSelectedRows {
  61.458 +            vm.handleUserClickedDestruktiveButton(forRowsAt: selectedIndexPaths)
  61.459 +        }
  61.460 +        cancelToolbar(sender)
  61.461 +    }
  61.462 +
  61.463 +    //recover the original toolbar and right button
  61.464 +    private func showStandardToolbar() {
  61.465 +        toolbarItems = tempToolbarItems
  61.466 +        navigationItem.rightBarButtonItem = editRightButton
  61.467 +    }
  61.468 +
  61.469 +    private func moveSelectionIfNeeded(fromIndexPath: IndexPath, toIndexPath: IndexPath) {
  61.470 +        if lastSelectedIndexPath == fromIndexPath {
  61.471 +            lastSelectedIndexPath = toIndexPath
  61.472 +            resetSelection()
  61.473 +        }
  61.474 +    }
  61.475 +
  61.476 +    private func resetSelection() {
  61.477 +        tableView.selectRow(at: lastSelectedIndexPath, animated: false, scrollPosition: .none)
  61.478 +    }
  61.479 +
  61.480 +    // MARK: - Action Filter Button
  61.481 +    
  61.482 +    @IBAction func filterButtonHasBeenPressed(_ sender: UIBarButtonItem) {
  61.483 +        guard let vm = viewModel else {
  61.484 +            Log.shared.errorAndCrash("We should have a model here")
  61.485 +            return
  61.486 +        }
  61.487 +        vm.isFilterEnabled = !vm.isFilterEnabled
  61.488 +        if vm.isFilterEnabled {
  61.489 +            let flexibleSpace = createFlexibleBarButtonItem()
  61.490 +            toolbarItems?.insert(textFilterButton, at: 1)
  61.491 +            toolbarItems?.insert(flexibleSpace, at: 1)
  61.492 +        } else {
  61.493 +            toolbarItems?.remove(at: 1)
  61.494 +            toolbarItems?.remove(at: 1)
  61.495 +
  61.496 +        }
  61.497 +        updateFilterButtonView()
  61.498 +    }
  61.499 +
  61.500 +    private func updateFilterButtonView() {
  61.501 +        guard let vm = viewModel else {
  61.502 +            Log.shared.errorAndCrash("We should have a model here")
  61.503 +            return
  61.504 +        }
  61.505 +
  61.506 +        textFilterButton.isEnabled = vm.isFilterEnabled
  61.507 +        if textFilterButton.isEnabled {
  61.508 +            enableFilterButton.image = UIImage(named: "unread-icon-active")
  61.509 +            updateFilterText()
  61.510 +        } else {
  61.511 +            textFilterButton.title = ""
  61.512 +            enableFilterButton.image = UIImage(named: "unread-icon")
  61.513 +        }
  61.514 +    }
  61.515 +    
  61.516 +    private func updateFilterText() {
  61.517 +        if let vm = viewModel {
  61.518 +            var txt = vm.currentFilter.getFilterText()
  61.519 +            if(txt.count > EmailListViewController.FILTER_TITLE_MAX_XAR){
  61.520 +                let prefix = txt.prefix(ofLength: EmailListViewController.FILTER_TITLE_MAX_XAR)
  61.521 +                txt = String(prefix)
  61.522 +                txt += "..."
  61.523 +            }
  61.524 +            if txt.isEmpty {
  61.525 +                txt = "none"
  61.526 +            }
  61.527 +            textFilterButton.title = "Filter by: " + txt
  61.528 +        }
  61.529 +    }
  61.530 +
  61.531 +    // MARK: -
  61.532 +
  61.533 +    override func didReceiveMemoryWarning() {
  61.534 +        viewModel?.freeMemory()
  61.535 +    }
  61.536 +}
  61.537 +
  61.538 +// MARK: - UITableViewDataSource & UITableViewDelegate
  61.539 +
  61.540 +extension EmailListViewController: UITableViewDataSource, UITableViewDelegate {
  61.541 +
  61.542 +    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  61.543 +        return viewModel?.rowCount ?? 0
  61.544 +    }
  61.545 +
  61.546 +    func tableView(_ tableView: UITableView,
  61.547 +                   cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  61.548 +
  61.549 +        let cell = tableView.dequeueReusableCell(withIdentifier: EmailListViewCell.storyboardId,
  61.550 +                                                 for: indexPath)
  61.551 +        if let theCell = cell as? EmailListViewCell {
  61.552 +            theCell.delegate = self
  61.553 +
  61.554 +            guard let viewModel = viewModel?.viewModel(for: indexPath.row) else {
  61.555 +                return cell
  61.556 +            }
  61.557 +            theCell.configure(for: viewModel)
  61.558 +        } else {
  61.559 +            Log.shared.errorAndCrash("dequeued wrong cell")
  61.560 +        }
  61.561 +
  61.562 +        //restores selection state for updated or replaced cells.
  61.563 +        if lastSelectedIndexPath == indexPath {
  61.564 +            tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none)
  61.565 +        }
  61.566 +
  61.567 +        return cell
  61.568 +    }
  61.569 +
  61.570 +    func tableView(_ tableView: UITableView,
  61.571 +                   editActionsForRowAt indexPath: IndexPath,
  61.572 +                   for orientation: SwipeActionsOrientation) -> [SwipeAction]? {
  61.573 +        if viewModel == nil {
  61.574 +            return nil
  61.575 +        }
  61.576 +
  61.577 +        // Create swipe actions, taking the currently displayed folder into account
  61.578 +        var swipeActions = [SwipeAction]()
  61.579 +
  61.580 +        guard let model = viewModel else {
  61.581 +            Log.shared.errorAndCrash("Should have VM")
  61.582 +            return nil
  61.583 +        }
  61.584 +
  61.585 +        // Delete or Archive
  61.586 +        let destructiveAction = model.getDestructiveAction(forMessageAt: indexPath.row)
  61.587 +        let archiveAction =
  61.588 +            SwipeAction(style: .destructive,
  61.589 +                        title: destructiveAction.title(forDisplayMode: .titleAndImage)) {
  61.590 +                            [weak self] action, indexPath in
  61.591 +                            guard let me = self else {
  61.592 +                                Log.shared.errorAndCrash("Lost MySelf")
  61.593 +                                return
  61.594 +                            }
  61.595 +                            me.swipeDelete = action
  61.596 +                            me.deleteAction(forCellAt: indexPath)
  61.597 +
  61.598 +        }
  61.599 +        configure(action: archiveAction, with: destructiveAction)
  61.600 +        swipeActions.append(archiveAction)
  61.601 +
  61.602 +        // Flag
  61.603 +        let flagActionDescription = model.getFlagAction(forMessageAt: indexPath.row)
  61.604 +        if let flagActionDescription = flagActionDescription {
  61.605 +            let flagAction = SwipeAction(style: .default, title: "Flag") {
  61.606 +                [weak self] action, indexPath in
  61.607 +                guard let me = self else {
  61.608 +                    Log.shared.errorAndCrash("Lost MySelf")
  61.609 +                    return
  61.610 +                }
  61.611 +                me.flagAction(forCellAt: indexPath)
  61.612 +            }
  61.613 +
  61.614 +            flagAction.hidesWhenSelected = true
  61.615 +
  61.616 +            configure(action: flagAction, with: flagActionDescription)
  61.617 +            swipeActions.append(flagAction)
  61.618 +        }
  61.619 +
  61.620 +        // More (reply++)
  61.621 +        let moreActionDescription = model.getMoreAction(forMessageAt: indexPath.row)
  61.622 +
  61.623 +        if let moreActionDescription = moreActionDescription {
  61.624 +            // Do not add "more" actions (reply...) to drafts or outbox.
  61.625 +            let moreAction = SwipeAction(style: .default, title: "More") {
  61.626 +                [weak self] action, indexPath in
  61.627 +                guard let me = self else {
  61.628 +                    Log.shared.errorAndCrash("Lost MySelf")
  61.629 +                    return
  61.630 +                }
  61.631 +                me.moreAction(forCellAt: indexPath)
  61.632 +            }
  61.633 +            moreAction.hidesWhenSelected = true
  61.634 +            configure(action: moreAction, with: moreActionDescription)
  61.635 +            swipeActions.append(moreAction)
  61.636 +        }
  61.637 +        return (orientation == .right ?   swipeActions : nil)
  61.638 +    }
  61.639 +
  61.640 +    func tableView(_ tableView: UITableView,
  61.641 +                   editActionsOptionsForRowAt indexPath: IndexPath,
  61.642 +                   for orientation: SwipeActionsOrientation) -> SwipeTableOptions {
  61.643 +        var options = SwipeTableOptions()
  61.644 +        options.transitionStyle = .border
  61.645 +        options.buttonSpacing = 11
  61.646 +        options.expansionStyle = .destructive(automaticallyDelete: false)
  61.647 +        return options
  61.648 +    }
  61.649 +
  61.650 +    func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
  61.651 +        guard let cell = cell as? EmailListViewCell else {
  61.652 +            return
  61.653 +        }
  61.654 +        cell.clear()
  61.655 +    }
  61.656 +
  61.657 +    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
  61.658 +        if tableView.isEditing {
  61.659 +            guard let vm = viewModel else {
  61.660 +                Log.shared.errorAndCrash("No VM")
  61.661 +                return
  61.662 +            }
  61.663 +            guard let selectedIndexPaths = tableView.indexPathsForSelectedRows else {
  61.664 +                // Nothing selected ...
  61.665 +                // ... nothing to do.
  61.666 +                return
  61.667 +            }
  61.668 +            vm.handleEditModeSelectionChange(selectedIndexPaths: selectedIndexPaths)
  61.669 +        } else {
  61.670 +            guard let vm = viewModel else {
  61.671 +                Log.shared.errorAndCrash("No VM")
  61.672 +                return
  61.673 +            }
  61.674 +            if vm.isSelectable(messageAt: indexPath) {
  61.675 +                lastSelectedIndexPath = indexPath
  61.676 +                tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none)
  61.677 +                if vm.isEditable(messageAt: indexPath) {
  61.678 +                    showEditDraftComposeView()
  61.679 +                } else {
  61.680 +                    showEmail(forCellAt: indexPath)
  61.681 +                }
  61.682 +            } else {
  61.683 +                tableView.deselectRow(at: indexPath, animated: true)
  61.684 +            }
  61.685 +        }
  61.686 +    }
  61.687 +
  61.688 +    func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
  61.689 +        if tableView.isEditing, let vm = viewModel {
  61.690 +            if let selectedIndexPaths = tableView.indexPathsForSelectedRows {
  61.691 +                vm.handleEditModeSelectionChange(selectedIndexPaths: selectedIndexPaths)
  61.692 +            } else {
  61.693 +                vm.handleEditModeSelectionChange(selectedIndexPaths: [])
  61.694 +            }
  61.695 +        }
  61.696 +    }
  61.697 +
  61.698 +    // Implemented to get informed about the scrolling position.
  61.699 +    // If the user has scrolled down (almost) to the end, we need to get older emails to display.
  61.700 +    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell,
  61.701 +                   forRowAt indexPath: IndexPath) {
  61.702 +        guard let vm = viewModel else {
  61.703 +            Log.shared.errorAndCrash("No model.")
  61.704 +            return
  61.705 +        }
  61.706 +        vm.fetchOlderMessagesIfRequired(forIndexPath: indexPath)
  61.707 +    }
  61.708 +
  61.709 +    // MARK: - SwipeTableViewCellDelegate
  61.710 +
  61.711 +    func configure(action: SwipeAction, with descriptor: SwipeActionDescriptor) {
  61.712 +        action.title = descriptor.title(forDisplayMode: buttonDisplayMode)
  61.713 +        action.image = descriptor.image(forStyle: buttonStyle, displayMode: buttonDisplayMode)
  61.714 +
  61.715 +        switch buttonStyle {
  61.716 +        case .backgroundColor:
  61.717 +            action.backgroundColor = descriptor.color
  61.718 +        case .circular:
  61.719 +            action.backgroundColor = .clear
  61.720 +            action.textColor = descriptor.color
  61.721 +            action.font = .systemFont(ofSize: 13)
  61.722 +            action.transitionDelegate = ScaleTransition.default
  61.723 +        }
  61.724 +    }
  61.725 +
  61.726 +    // MARK: - Manipulating the (master) bottom toolbar
  61.727 +
  61.728 +    /// Our own factory method for creating pEp bar button items,
  61.729 +    /// tagged so we recognize them later, for easy removal.
  61.730 +    private func createPepBarButtonItem() -> UIBarButtonItem {
  61.731 +        let item = UIBarButtonItem.getPEPButton(
  61.732 +            action: #selector(showSettingsViewController),
  61.733 +            target: self)
  61.734 +        item.tag = pEpButtonItemTag
  61.735 +        return item
  61.736 +    }
  61.737 +
  61.738 +    /// Our own factory method for creating flexible space bar button items,
  61.739 +    /// tagged so we recognize them later, for easy removal.
  61.740 +    private func createFlexibleBarButtonItem() -> UIBarButtonItem {
  61.741 +        let item = UIBarButtonItem(
  61.742 +            barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace,
  61.743 +            target: nil,
  61.744 +            action: nil)
  61.745 +        item.tag = flexibleSpaceButtonItemTag
  61.746 +        return item
  61.747 +    }
  61.748 +
  61.749 +    /// - Returns: A new array of `UIBarButtonItem`s with trailing flexible whitespace
  61.750 +    /// removed (at least the ones created by our own factory method).
  61.751 +    /// - Parameter barButtonItems: The bar button items to remove from.
  61.752 +    private func trailingFlexibleSpaceRemoved(barButtonItems: [UIBarButtonItem]) -> [UIBarButtonItem] {
  61.753 +        var theItems = barButtonItems
  61.754 +        while true {
  61.755 +            if let lastItem = theItems.last {
  61.756 +                if lastItem.tag == flexibleSpaceButtonItemTag {
  61.757 +                    theItems.removeLast()
  61.758 +                } else {
  61.759 +                    break
  61.760 +                }
  61.761 +            } else {
  61.762 +                break
  61.763 +            }
  61.764 +        }
  61.765 +        return theItems
  61.766 +    }
  61.767 +
  61.768 +    /// Shows the pEp logo (leading to the settings) in the master view bottom toolbar,
  61.769 +    /// or not, depending on `show`.
  61.770 +    private func showLogoInMasterToolbar(show: Bool) {
  61.771 +        // persist this state
  61.772 +        shouldShowPepButtonInMasterToolbar = show
  61.773 +
  61.774 +        if show {
  61.775 +            if var barItems = toolbarItems {
  61.776 +                if let lastItem = barItems.last, lastItem.tag == pEpButtonItemTag {
  61.777 +                    // already there
  61.778 +                    return
  61.779 +                } else {
  61.780 +                    barItems.append(contentsOf: [createFlexibleBarButtonItem(),
  61.781 +                                                 createPepBarButtonItem()])
  61.782 +                }
  61.783 +                toolbarItems = barItems
  61.784 +            } else {
  61.785 +                toolbarItems = [createPepBarButtonItem()]
  61.786 +            }
  61.787 +        } else {
  61.788 +            if var barItems = toolbarItems {
  61.789 +                if let lastItem = barItems.last, lastItem.tag == pEpButtonItemTag {
  61.790 +                    barItems.removeLast()
  61.791 +                }
  61.792 +                toolbarItems = trailingFlexibleSpaceRemoved(barButtonItems: barItems)
  61.793 +            }
  61.794 +        }
  61.795 +    }
  61.796 +
  61.797 +    /// Tries to deduce from the split view arrangement whether to show the
  61.798 +    /// master toolbar pEp logo or not.
  61.799 +    private func checkSplitViewState() {
  61.800 +        if let spvc = splitViewController {
  61.801 +            if spvc.viewControllers.count == 1 {
  61.802 +                // only master is shown
  61.803 +                showLogoInMasterToolbar(show: true)
  61.804 +            } else if spvc.viewControllers.count == 2 {
  61.805 +                // detail is shown, check further
  61.806 +                var showMasterLogo = true
  61.807 +                if let vc = spvc.viewControllers[safe: 1] {
  61.808 +                    if vc is NothingSelectedViewController {
  61.809 +                        showMasterLogo = true
  61.810 +                    } else {
  61.811 +                        showMasterLogo = false
  61.812 +                    }
  61.813 +                }
  61.814 +                showLogoInMasterToolbar(show: showMasterLogo)
  61.815 +            }
  61.816 +        }
  61.817 +    }
  61.818 +
  61.819 +    // MARK: - Observing the split view controller
  61.820 +
  61.821 +    //???: Hard to undestand. What is the observeer used for? Out of 3 devs, zero understood.
  61.822 +
  61.823 +    /// Start observing the view controllers in the split view.
  61.824 +    private func watchDetailView() {
  61.825 +        if !observingSplitViewControllers, let spvc = splitViewController {
  61.826 +            spvc.addObserver(self,
  61.827 +                             forKeyPath: splitViewObserverKeyPath,
  61.828 +                             options: [],
  61.829 +                             context: nil)
  61.830 +            observingSplitViewControllers = true
  61.831 +        }
  61.832 +    }
  61.833 +
  61.834 +    /// Stop listening for changes in the view controllers in the split view.
  61.835 +    private func unwatchDetailView() {
  61.836 +        if observingSplitViewControllers, let spvc = splitViewController {
  61.837 +            spvc.removeObserver(self, forKeyPath: splitViewObserverKeyPath)
  61.838 +            observingSplitViewControllers = false
  61.839 +        }
  61.840 +    }
  61.841 +
  61.842 +    /// React to changes to the view controllers of our split view controller.
  61.843 +    override func observeValue(forKeyPath keyPath: String?,
  61.844 +                               of object: Any?,
  61.845 +                               change: [NSKeyValueChangeKey : Any]?,
  61.846 +                               context: UnsafeMutableRawPointer?) {
  61.847 +        if keyPath != splitViewObserverKeyPath {
  61.848 +            super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
  61.849 +            return
  61.850 +        }
  61.851 +
  61.852 +        checkSplitViewState()
  61.853 +    }
  61.854 +}
  61.855 +
  61.856 +// MARK: - UISearchResultsUpdating, UISearchControllerDelegate
  61.857 +
  61.858 +extension EmailListViewController: UISearchResultsUpdating, UISearchControllerDelegate {
  61.859 +
  61.860 +    public func updateSearchResults(for searchController: UISearchController) {
  61.861 +        guard
  61.862 +            let vm = viewModel,
  61.863 +            let searchText = searchController.searchBar.text
  61.864 +            else {
  61.865 +                return
  61.866 +        }
  61.867 +        vm.handleSearchTermChange(newSearchTerm: searchText)
  61.868 +    }
  61.869 +
  61.870 +    func didDismissSearchController(_ searchController: UISearchController) {
  61.871 +        guard let vm = viewModel else {
  61.872 +            Log.shared.errorAndCrash("No chance to remove filter, sorry.")
  61.873 +            return
  61.874 +        }
  61.875 +        vm.handleSearchControllerDidDisappear()
  61.876 +    }
  61.877 +}
  61.878 +
  61.879 +// MARK: - EmailListViewModelDelegate
  61.880 +
  61.881 +extension EmailListViewController: EmailListViewModelDelegate {
  61.882 +
  61.883 +    func checkIfSplitNeedsUpdate(indexpath: [IndexPath]) {
  61.884 +        guard let last = lastSelectedIndexPath else {
  61.885 +            return
  61.886 +        }
  61.887 +        if !onlySplitViewMasterIsShown && indexpath.contains(last) {
  61.888 +            showEmail(forCellAt: last)
  61.889 +        }
  61.890 +    }
  61.891 +
  61.892 +    func reloadData(viewModel: EmailDisplayViewModel) {
  61.893 +        tableView.reloadData()
  61.894 +    }
  61.895 +
  61.896 +    func willReceiveUpdates(viewModel: EmailDisplayViewModel) {
  61.897 +        tableView.beginUpdates()
  61.898 +    }
  61.899 +
  61.900 +    func allUpdatesReceived(viewModel: EmailDisplayViewModel) {
  61.901 +        tableView.endUpdates()
  61.902 +    }
  61.903 +
  61.904 +    func setToolbarItemsEnabledState(to newValue: Bool) {
  61.905 +        if viewModel?.shouldShowToolbarEditButtons ?? true {
  61.906 +            // Never enable those for outbox
  61.907 +            flagToolbarButton?.isEnabled = newValue
  61.908 +            unflagToolbarButton?.isEnabled = newValue
  61.909 +            readToolbarButton?.isEnabled = newValue
  61.910 +            unreadToolbarButton?.isEnabled = newValue
  61.911 +            moveToolbarButton?.isEnabled = newValue
  61.912 +        }
  61.913 +        deleteToolbarButton?.isEnabled = newValue
  61.914 +    }
  61.915 +
  61.916 +    func showUnflagButton(enabled: Bool) {
  61.917 +        if enabled {
  61.918 +
  61.919 +            if let button = unflagToolbarButton {
  61.920 +                toolbarItems?.remove(at: 0)
  61.921 +                toolbarItems?.insert(button, at: 0)
  61.922 +            }
  61.923 +
  61.924 +        } else {
  61.925 +            if let button = flagToolbarButton {
  61.926 +                toolbarItems?.remove(at: 0)
  61.927 +                toolbarItems?.insert(button, at: 0)
  61.928 +            }
  61.929 +        }
  61.930 +    }
  61.931 +
  61.932 +    func showUnreadButton(enabled: Bool) {
  61.933 +        if enabled {
  61.934 +            if let button = unreadToolbarButton {
  61.935 +                toolbarItems?.remove(at: 2)
  61.936 +                toolbarItems?.insert(button, at: 2)
  61.937 +            }
  61.938 +        } else {
  61.939 +            if let button = readToolbarButton {
  61.940 +                toolbarItems?.remove(at: 2)
  61.941 +                toolbarItems?.insert(button, at: 2)
  61.942 +            }
  61.943 +        }
  61.944 +    }
  61.945 +
  61.946 +    func select(itemAt indexPath: IndexPath) {
  61.947 +        guard !onlySplitViewMasterIsShown else {
  61.948 +            // We want to follow EmailDetailViewSelection only if it is shown at the same time (if
  61.949 +            // master/EmailList_and_ detail/EmailDetail views are both currently shown).
  61.950 +            tableView.deselectRow(at: indexPath, animated: true)
  61.951 +            return
  61.952 +        }
  61.953 +
  61.954 +        let cell = tableView.cellForRow(at: indexPath)
  61.955 +        guard !(cell?.isSelected ?? false) else {
  61.956 +            // the cell is already selected. Nothing to do
  61.957 +            return
  61.958 +        }
  61.959 +
  61.960 +        // Select the cell shown in DetailView and scroll to it (nicely animated) in case it is
  61.961 +        // currently not visible.
  61.962 +        guard let visibleIndexPaths = tableView.indexPathsForVisibleRows else {
  61.963 +            Log.shared.errorAndCrash("No visible rows")
  61.964 +            return
  61.965 +        }
  61.966 +        //        let visibleIndexPaths = tableView.indexPathsForVisibleRows
  61.967 +        let cellIsAlreadyVisible = visibleIndexPaths.contains(indexPath)
  61.968 +        let scrollPosition: UITableView.ScrollPosition
  61.969 +        if cellIsAlreadyVisible {
  61.970 +            scrollPosition = .none
  61.971 +        } else {
  61.972 +            if let lastIndex = visibleIndexPaths.last {
  61.973 +                let cellIsBelowVisibleRect = indexPath.row > lastIndex.row
  61.974 +                scrollPosition = cellIsBelowVisibleRect ? .bottom : .top
  61.975 +            } else {
  61.976 +                scrollPosition = .top
  61.977 +            }
  61.978 +        }
  61.979 +        tableView.selectRow(at: indexPath,
  61.980 +                            animated: cellIsAlreadyVisible ? false : true,
  61.981 +                            scrollPosition: scrollPosition)
  61.982 +    }
  61.983 +
  61.984 +    func emailListViewModel(viewModel: EmailDisplayViewModel, didInsertDataAt indexPaths: [IndexPath]) {
  61.985 +        lastSelectedIndexPath = nil
  61.986 +        tableView.insertRows(at: indexPaths, with: .automatic)
  61.987 +    }
  61.988 +
  61.989 +    func emailListViewModel(viewModel: EmailDisplayViewModel, didRemoveDataAt indexPaths: [IndexPath]) {
  61.990 +        lastSelectedIndexPath = tableView.indexPathForSelectedRow ?? lastSelectedIndexPath
  61.991 +
  61.992 +        if let swipeDelete = self.swipeDelete {
  61.993 +            swipeDelete.fulfill(with: .delete)
  61.994 +            self.swipeDelete = nil
  61.995 +        } else {
  61.996 +            tableView.deleteRows(at: indexPaths, with: .automatic)
  61.997 +        }
  61.998 +        if viewModel.rowCount == 0 {
  61.999 +            showNoMessageSelected()
 61.1000 +        }
 61.1001 +    }
 61.1002 +
 61.1003 +    func emailListViewModel(viewModel: EmailDisplayViewModel,
 61.1004 +                            didUpdateDataAt indexPaths: [IndexPath]) {
 61.1005 +        lastSelectedIndexPath = tableView.indexPathForSelectedRow
 61.1006 +        tableView.reloadRows(at: indexPaths, with: .none)
 61.1007 +        // In case the cell was selected before reloading, set it selected after reloading too.
 61.1008 +        guard let lastSelectedIndexPath = lastSelectedIndexPath, // Nothing selected, nothing to do.
 61.1009 +            indexPaths.contains(lastSelectedIndexPath) else { // the reloaded cell(s) where not selected
 61.1010 +            return
 61.1011 +        }
 61.1012 +        indexPaths.forEach {
 61.1013 +            if $0 == lastSelectedIndexPath {
 61.1014 +                let cell = tableView.cellForRow(at: $0)
 61.1015 +                cell?.isSelected = true
 61.1016 +            }
 61.1017 +        }
 61.1018 +
 61.1019 +    }
 61.1020 +
 61.1021 +    func emailListViewModel(viewModel: EmailDisplayViewModel,
 61.1022 +                            didMoveData atIndexPath: IndexPath,
 61.1023 +                            toIndexPath: IndexPath) {
 61.1024 +        lastSelectedIndexPath = tableView.indexPathForSelectedRow
 61.1025 +        tableView.moveRow(at: atIndexPath, to: toIndexPath)
 61.1026 +        moveSelectionIfNeeded(fromIndexPath: atIndexPath, toIndexPath: toIndexPath)
 61.1027 +    }
 61.1028 +}
 61.1029 +
 61.1030 +// MARK: - ActionSheet & ActionSheet Actions
 61.1031 +
 61.1032 +extension EmailListViewController {
 61.1033 +    func showMoreActionSheet(forRowAt indexPath: IndexPath) {
 61.1034 +        lastSelectedIndexPath = indexPath
 61.1035 +        let alertControler = UIAlertController.pEpAlertController(
 61.1036 +            title: nil, message: nil, preferredStyle: .actionSheet)
 61.1037 +        let cancelAction = createCancelAction()
 61.1038 +        let replyAction = createReplyAction()
 61.1039 +
 61.1040 +        let replyAllAction = createReplyAllAction(forRowAt: indexPath)
 61.1041 +        let readAction = createReadOrUnReadAction(forRowAt: indexPath)
 61.1042 +
 61.1043 +        let forwardAction = createForwardAction()
 61.1044 +        let moveToFolderAction = createMoveToFolderAction()
 61.1045 +
 61.1046 +        alertControler.addAction(cancelAction)
 61.1047 +        alertControler.addAction(replyAction)
 61.1048 +
 61.1049 +        if let theReplyAllAction = replyAllAction {
 61.1050 +            alertControler.addAction(theReplyAllAction)
 61.1051 +        }
 61.1052 +
 61.1053 +        alertControler.addAction(forwardAction)
 61.1054 +        alertControler.addAction(moveToFolderAction)
 61.1055 +        alertControler.addAction(readAction)
 61.1056 +
 61.1057 +        if let popoverPresentationController = alertControler.popoverPresentationController {
 61.1058 +            popoverPresentationController.sourceView = tableView
 61.1059 +            let cellFrame = tableView.rectForRow(at: indexPath)
 61.1060 +            let sourceRect = view.convert(cellFrame, from: tableView)
 61.1061 +            popoverPresentationController.sourceRect = sourceRect
 61.1062 +
 61.1063 +        }
 61.1064 +        present(alertControler, animated: true, completion: nil)
 61.1065 +    }
 61.1066 +
 61.1067 +    // MARK: Action Sheet Actions
 61.1068 +
 61.1069 +    private func createMoveToFolderAction() -> UIAlertAction {
 61.1070 +        let title = NSLocalizedString("Move to Folder", comment: "EmailList action title")
 61.1071 +        return UIAlertAction(title: title, style: .default) { [weak self] action in
 61.1072 +            guard let me = self else {
 61.1073 +                Log.shared.errorAndCrash("Lost MySelf")
 61.1074 +                return
 61.1075 +            }
 61.1076 +            me.performSegue(withIdentifier: .segueShowMoveToFolder, sender: me)
 61.1077 +        }
 61.1078 +    }
 61.1079 +
 61.1080 +    private func createReadOrUnReadAction(forRowAt indexPath: IndexPath) -> UIAlertAction {
 61.1081 +        let seenState = viewModel?.viewModel(for: indexPath.row)?.isSeen ?? false
 61.1082 +
 61.1083 +        var title = ""
 61.1084 +        if seenState {
 61.1085 +            title = NSLocalizedString("Mark as unread", comment: "EmailList action title")
 61.1086 +        } else {
 61.1087 +            title = NSLocalizedString("Mark as Read", comment: "EmailList action title")
 61.1088 +        }
 61.1089 +
 61.1090 +        return UIAlertAction(title: title, style: .default) { [weak self] action in
 61.1091 +            guard let me = self else {
 61.1092 +                Log.shared.errorAndCrash("Lost MySelf")
 61.1093 +                return
 61.1094 +            }
 61.1095 +            guard let cell = me.tableView.cellForRow(at: indexPath) as? EmailListViewCell else {
 61.1096 +                Log.shared.errorAndCrash(message: "Cell type is wrong")
 61.1097 +                return
 61.1098 +            }
 61.1099 +            cell.isSeen = !seenState
 61.1100 +            if seenState {
 61.1101 +                me.viewModel?.markAsUnread(indexPaths: [indexPath])
 61.1102 +            } else {
 61.1103 +                me.viewModel?.markAsRead(indexPaths: [indexPath])
 61.1104 +            }
 61.1105 +        }
 61.1106 +    }
 61.1107 +
 61.1108 +    func createCancelAction() -> UIAlertAction {
 61.1109 +        let title = NSLocalizedString("Cancel", comment: "EmailList action title")
 61.1110 +        return  UIAlertAction(title: title, style: .cancel) {
 61.1111 +            [weak self] action in
 61.1112 +            guard let me = self else {
 61.1113 +                Log.shared.errorAndCrash("Lost MySelf")
 61.1114 +                return
 61.1115 +            }
 61.1116 +            me.tableView.beginUpdates()
 61.1117 +            me.tableView.setEditing(false, animated: true)
 61.1118 +            me.tableView.endUpdates()
 61.1119 +        }
 61.1120 +    }
 61.1121 +
 61.1122 +    func createReplyAction() ->  UIAlertAction {
 61.1123 +        let title = NSLocalizedString("Reply", comment: "EmailList action title")
 61.1124 +        return UIAlertAction(title: title, style: .default) {
 61.1125 +            [weak self] action in
 61.1126 +            guard let me = self else {
 61.1127 +                Log.shared.errorAndCrash("Lost MySelf")
 61.1128 +                return
 61.1129 +            }
 61.1130 +            me.performSegue(withIdentifier: .segueReply, sender: me)
 61.1131 +        }
 61.1132 +    }
 61.1133 +
 61.1134 +    func createReplyAllAction(forRowAt indexPath: IndexPath) ->  UIAlertAction? {
 61.1135 +        guard let vm = viewModel else {
 61.1136 +            Log.shared.errorAndCrash("No VM")
 61.1137 +            return nil
 61.1138 +        }
 61.1139 +        if (vm.isReplyAllPossible(forRowAt: indexPath)) {
 61.1140 +            let title = NSLocalizedString("Reply All", comment: "EmailList action title")
 61.1141 +            return UIAlertAction(title: title, style: .default) {
 61.1142 +                [weak self] action in
 61.1143 +                guard let me = self else {
 61.1144 +                    Log.shared.errorAndCrash("Lost MySelf")
 61.1145 +                    return
 61.1146 +                }
 61.1147 +                me.performSegue(withIdentifier: .segueReplyAll, sender: me)
 61.1148 +            }
 61.1149 +        } else {
 61.1150 +            return nil
 61.1151 +        }
 61.1152 +    }
 61.1153 +
 61.1154 +    func createForwardAction() -> UIAlertAction {
 61.1155 +        let title = NSLocalizedString("Forward", comment: "EmailList action title")
 61.1156 +        return UIAlertAction(title: title, style: .default) {
 61.1157 +            [weak self] action in
 61.1158 +            guard let me = self else {
 61.1159 +                Log.shared.errorAndCrash("Lost MySelf")
 61.1160 +                return
 61.1161 +            }
 61.1162 +            me.performSegue(withIdentifier: .segueForward, sender: me)
 61.1163 +        }
 61.1164 +    }
 61.1165 +}
 61.1166 +
 61.1167 +// MARK: - TableViewCell Actions
 61.1168 +
 61.1169 +extension EmailListViewController {
 61.1170 +    private func createRowAction(image: UIImage?,
 61.1171 +                                 action: @escaping (UITableViewRowAction, IndexPath) -> Void
 61.1172 +    ) -> UITableViewRowAction {
 61.1173 +        let rowAction = UITableViewRowAction(style: .normal, title: nil, handler: action)
 61.1174 +        if let theImage = image {
 61.1175 +            let iconColor = UIColor(patternImage: theImage)
 61.1176 +            rowAction.backgroundColor = iconColor
 61.1177 +        }
 61.1178 +        return rowAction
 61.1179 +    }
 61.1180 +
 61.1181 +    func flagAction(forCellAt indexPath: IndexPath) {
 61.1182 +        guard let row = viewModel?.viewModel(for: indexPath.row) else {
 61.1183 +            Log.shared.errorAndCrash("No data for indexPath!")
 61.1184 +            return
 61.1185 +        }
 61.1186 +        guard let cell = self.tableView.cellForRow(at: indexPath) as? EmailListViewCell else {
 61.1187 +            Log.shared.errorAndCrash("No cell for indexPath!")
 61.1188 +            return
 61.1189 +        }
 61.1190 +        if row.isFlagged {
 61.1191 +            viewModel?.markAsUnFlagged(indexPaths: [indexPath])
 61.1192 +            cell.isFlagged = false
 61.1193 +        } else {
 61.1194 +            viewModel?.markAsFlagged(indexPaths: [indexPath])
 61.1195 +            cell.isFlagged = true
 61.1196 +        }
 61.1197 +    }
 61.1198 +
 61.1199 +    func deleteAction(forCellAt indexPath: IndexPath) {
 61.1200 +        viewModel?.delete(forIndexPath: indexPath)
 61.1201 +    }
 61.1202 +
 61.1203 +    func moreAction(forCellAt indexPath: IndexPath) {
 61.1204 +        showMoreActionSheet(forRowAt: indexPath)
 61.1205 +    }
 61.1206 +}
 61.1207 +
 61.1208 +// MARK: - Segue handling
 61.1209 +
 61.1210 +extension EmailListViewController {
 61.1211 +    /**
 61.1212 +     Enables manual account setup to unwind to the unified inbox.
 61.1213 +     */
 61.1214 +    @IBAction func segueUnwindAfterAccountCreation(segue:UIStoryboardSegue) {
 61.1215 +        setup()
 61.1216 +    }
 61.1217 +}
 61.1218 +
 61.1219 +// MARK: - SegueHandlerType
 61.1220 +
 61.1221 +extension EmailListViewController: SegueHandlerType {
 61.1222 +    
 61.1223 +    enum SegueIdentifier: String {
 61.1224 +        case segueAddNewAccount
 61.1225 +        case segueShowEmailSplitView
 61.1226 +        case segueShowEmailNotSplitView
 61.1227 +        case segueCompose
 61.1228 +        case segueReply
 61.1229 +        case segueReplyAll
 61.1230 +        case segueForward
 61.1231 +        case segueEditDraft
 61.1232 +        case segueShowFilter
 61.1233 +        case segueFolderViews
 61.1234 +        case segueShowMoveToFolder
 61.1235 +        case segueShowThreadedEmail
 61.1236 +        case noSegue
 61.1237 +    }
 61.1238 +    
 61.1239 +    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
 61.1240 +        let segueId = segueIdentifier(for: segue)
 61.1241 +        switch segueId {
 61.1242 +        case .segueReply,
 61.1243 +             .segueReplyAll,
 61.1244 +             .segueForward,
 61.1245 +             .segueCompose,
 61.1246 +             .segueEditDraft:
 61.1247 +            setupComposeViewController(for: segue)
 61.1248 +        case .segueShowEmailNotSplitView, .segueShowEmailSplitView:
 61.1249 +            guard
 61.1250 +                let nav = segue.destination as? UINavigationController,
 61.1251 +                let vc = nav.rootViewController as? EmailDetailViewController,
 61.1252 +                let indexPath = lastSelectedIndexPath else {
 61.1253 +                    Log.shared.errorAndCrash("Segue issue")
 61.1254 +                    return
 61.1255 +            }
 61.1256 +            vc.appConfig = appConfig
 61.1257 +            vc.viewModel = viewModel?.emailDetialViewModel()
 61.1258 +            vc.firstItemToShow = indexPath
 61.1259 +        case .segueShowFilter:
 61.1260 +            guard let destiny = segue.destination as? FilterTableViewController else {
 61.1261 +                Log.shared.errorAndCrash("Segue issue")
 61.1262 +                return
 61.1263 +            }
 61.1264 +            guard let vm = viewModel else {
 61.1265 +                Log.shared.errorAndCrash("No VM")
 61.1266 +                return
 61.1267 +            }
 61.1268 +            destiny.appConfig = appConfig
 61.1269 +            destiny.filterDelegate = vm
 61.1270 +            destiny.filterEnabled = vm.currentFilter
 61.1271 +            destiny.hidesBottomBarWhenPushed = true
 61.1272 +        case .segueAddNewAccount:
 61.1273 +            guard
 61.1274 +                let nav = segue.destination as? UINavigationController,
 61.1275 +                let vc = nav.rootViewController as? LoginViewController else {
 61.1276 +                    Log.shared.errorAndCrash("Segue issue")
 61.1277 +                    return
 61.1278 +            }
 61.1279 +            vc.appConfig = appConfig
 61.1280 +            vc.delegate = self
 61.1281 +            vc.hidesBottomBarWhenPushed = true
 61.1282 +            break
 61.1283 +        case .segueFolderViews:
 61.1284 +            guard let vC = segue.destination as? FolderTableViewController  else {
 61.1285 +                Log.shared.errorAndCrash("Segue issue")
 61.1286 +                return
 61.1287 +            }
 61.1288 +            vC.appConfig = appConfig
 61.1289 +            break
 61.1290 +        case .segueShowMoveToFolder:
 61.1291 +            var selectedRows: [IndexPath] = []
 61.1292 +
 61.1293 +            if let selectedItems = tableView.indexPathsForSelectedRows {
 61.1294 +                selectedRows = selectedItems
 61.1295 +            } else if let last = lastSelectedIndexPath {
 61.1296 +                selectedRows.append(last)
 61.1297 +            }
 61.1298 +
 61.1299 +            guard  let nav = segue.destination as? UINavigationController,
 61.1300 +                let destination = nav.topViewController as? MoveToAccountViewController
 61.1301 +                else {
 61.1302 +                    Log.shared.errorAndCrash("No DVC?")
 61.1303 +                    break
 61.1304 +            }
 61.1305 +
 61.1306 +            destination.viewModel
 61.1307 +                = viewModel?.getMoveToFolderViewModel(forSelectedMessages: selectedRows)
 61.1308 +            destination.appConfig = appConfig
 61.1309 +            break
 61.1310 +        default:
 61.1311 +            Log.shared.errorAndCrash("Unhandled segue")
 61.1312 +            break
 61.1313 +        }
 61.1314 +    }
 61.1315 +
 61.1316 +    @IBAction func segueUnwindAccountAdded(segue: UIStoryboardSegue) {
 61.1317 +        // nothing to do.
 61.1318 +    }
 61.1319 +
 61.1320 +    private func setupComposeViewController(for segue: UIStoryboardSegue) {
 61.1321 +        let segueId = segueIdentifier(for: segue)
 61.1322 +        guard
 61.1323 +            let nav = segue.destination as? UINavigationController,
 61.1324 +            let composeVc = nav.topViewController as? ComposeTableViewController,
 61.1325 +            let composeMode = composeMode(for: segueId),
 61.1326 +            let vm = viewModel else {
 61.1327 +                Log.shared.errorAndCrash("composeViewController setup issue")
 61.1328 +                return
 61.1329 +        }
 61.1330 +        composeVc.appConfig = appConfig
 61.1331 +
 61.1332 +        if segueId != .segueCompose {
 61.1333 +            // This is not a simple compose (but reply, forward or such),
 61.1334 +            // thus we have to pass the original message.
 61.1335 +            guard let indexPath = lastSelectedIndexPath else {
 61.1336 +                Log.shared.info("Can happen if the message the user wanted to reply to has been deleted in between performeSeque and here")
 61.1337 +                return
 61.1338 +            }
 61.1339 +
 61.1340 +            composeVc.viewModel = vm.composeViewModel(forMessageRepresentedByItemAt: indexPath,
 61.1341 +                                                      composeMode: composeMode)
 61.1342 +        } else {
 61.1343 +            composeVc.viewModel = vm.composeViewModelForNewMessage()
 61.1344 +        }
 61.1345 +    }
 61.1346 +
 61.1347 +    private func composeMode(for segueId: SegueIdentifier) -> ComposeUtil.ComposeMode? {
 61.1348 +        switch segueId {
 61.1349 +        case .segueReply:
 61.1350 +            return .replyFrom
 61.1351 +        case .segueReplyAll:
 61.1352 +            return .replyAll
 61.1353 +        case .segueForward:
 61.1354 +            return .forward
 61.1355 +        case .segueCompose:
 61.1356 +            return .normal
 61.1357 +        case .segueEditDraft:
 61.1358 +            return .normal
 61.1359 +        default:
 61.1360 +            return nil
 61.1361 +        }
 61.1362 +    }
 61.1363 +}
 61.1364 +
 61.1365 +// MARK: - LoginViewControllerDelegate
 61.1366 +
 61.1367 +extension EmailListViewController: LoginViewControllerDelegate {
 61.1368 +    
 61.1369 +    func loginViewControllerDidCreateNewAccount(_ loginViewController: LoginViewController) {
 61.1370 +        // Setup model after initial account setup
 61.1371 +        setup()
 61.1372 +    }
 61.1373 +}
    62.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    62.2 +++ b/pEpForiOS/UI/EmailDisplay/EmailDisplayList/EmailListViewModel.swift	Fri Feb 07 12:31:01 2020 +0100
    62.3 @@ -0,0 +1,497 @@
    62.4 +//
    62.5 +//  EmailListViewModel.swift
    62.6 +//  pEpForiOS
    62.7 +//
    62.8 +//  Created by Xavier Algarra on 23/06/2017.
    62.9 +//  Copyright © 2017 p≡p Security S.A. All rights reserved.
   62.10 +//
   62.11 +
   62.12 +import Foundation
   62.13 +import pEpIOSToolbox
   62.14 +import MessageModel
   62.15 +import PEPObjCAdapterFramework
   62.16 +
   62.17 +
   62.18 +protocol EmailListViewModelDelegate: EmailDisplayViewModelDelegate {
   62.19 +    func setToolbarItemsEnabledState(to newValue: Bool)
   62.20 +    func showUnflagButton(enabled: Bool)
   62.21 +    func showUnreadButton(enabled: Bool)
   62.22 +    func select(itemAt indexPath: IndexPath)
   62.23 +}
   62.24 +
   62.25 +// MARK: - EmailListViewModel
   62.26 +
   62.27 +class EmailListViewModel: EmailDisplayViewModel {
   62.28 +    private var emailDetailViewModel: EmailDetailViewModel?
   62.29 +    private let contactImageTool = IdentityImageTool()
   62.30 +
   62.31 +    private var lastSearchTerm = ""
   62.32 +    private var updatesEnabled = true
   62.33 +
   62.34 +    // MARK: - Life Cycle
   62.35 +
   62.36 +    init(delegate: EmailListViewModelDelegate? = nil, folderToShow: DisplayableFolderProtocol) {
   62.37 +        self.folderToShow = folderToShow
   62.38 +        let messageQueryResults = MessageQueryResults(withFolder: folderToShow,
   62.39 +                                                      filter: nil,
   62.40 +                                                      search: nil)
   62.41 +        super.init(delegate: delegate, messageQueryResults: messageQueryResults)
   62.42 +        self.messageQueryResults.rowDelegate = self
   62.43 +    }
   62.44 +
   62.45 +    // MARK: - EmailListViewModelProtocol
   62.46 +
   62.47 +    private var _currentFilter: MessageQueryResultsFilter?
   62.48 +    public private(set) var currentFilter: MessageQueryResultsFilter {
   62.49 +        get {
   62.50 +            if let cf = _currentFilter {
   62.51 +                return cf
   62.52 +            } else {
   62.53 +                return folderToShow.defaultFilter
   62.54 +            }
   62.55 +        }
   62.56 +        set {
   62.57 +            _currentFilter = newValue
   62.58 +        }
   62.59 +    }
   62.60 +
   62.61 +    public var isFilterEnabled = false {
   62.62 +        didSet {
   62.63 +            if oldValue != isFilterEnabled {
   62.64 +                handleFilterEnabledStateChange()
   62.65 +            }
   62.66 +        }
   62.67 +    }
   62.68 +
   62.69 +    public let folderToShow: DisplayableFolderProtocol
   62.70 +
   62.71 +    public var folderName: String {
   62.72 +        return Folder.localizedName(realName: folderToShow.title)
   62.73 +    }
   62.74 +
   62.75 +    /// - Parameter indexPath: indexPath to check editability for.
   62.76 +    /// - returns:  Whether or not to show compose view rather then the email for message
   62.77 +    ///             represented by row at given `indexPath`.
   62.78 +    public func isEditable(messageAt indexPath: IndexPath) -> Bool {
   62.79 +        let message = messageQueryResults[indexPath.row]
   62.80 +        if message.parent.folderType == .drafts {
   62.81 +            return true
   62.82 +        } else {
   62.83 +            return false
   62.84 +        }
   62.85 +    }
   62.86 +
   62.87 +    public func isSelectable(messageAt indexPath: IndexPath) -> Bool {
   62.88 +        let message = messageQueryResults[indexPath.row]
   62.89 +        if message.parent.folderType == .outbox {
   62.90 +            return false
   62.91 +        } else {
   62.92 +            return true
   62.93 +        }
   62.94 +    }
   62.95 +
   62.96 +    /// - Parameter indexPath: indexPath to get viewModel for
   62.97 +    /// - returns: ViewModel to configure Cell with
   62.98 +    public func viewModel(for index: Int) -> MessageViewModel? {
   62.99 +        let messageViewModel = MessageViewModel(with: messageQueryResults[index])
  62.100 +        return messageViewModel
  62.101 +    }
  62.102 +
  62.103 +    /// Whether or not mails in the current folder are editable
  62.104 +    public var shouldShowToolbarEditButtons: Bool {
  62.105 +        switch folderToShow {
  62.106 +        case is VirtualFolderProtocol:
  62.107 +            return true
  62.108 +        case let folder as Folder:
  62.109 +            return folder.folderType != .outbox && folder.folderType != .drafts
  62.110 +        default:
  62.111 +            return true
  62.112 +        }
  62.113 +    }
  62.114 +
  62.115 +    /// Whether or not to show the Tutorial
  62.116 +    public var shouldShowTutorialWizard: Bool {
  62.117 +        return AppSettings.shared.shouldShowTutorialWizard
  62.118 +    }
  62.119 +
  62.120 +    /// Call when the tutorial has been displayed to the user
  62.121 +    public func didShowTutorialWizard() {
  62.122 +        AppSettings.shared.shouldShowTutorialWizard = false
  62.123 +    }
  62.124 +
  62.125 +    /// - returns: action to trigger if user clicks destructive button
  62.126 +    public func getDestructiveAction(forMessageAt index: Int) -> SwipeActionDescriptor {
  62.127 +        let parentFolder = getParentFolder(forMessageAt: index)
  62.128 +        let defaultDestructiveAction: SwipeActionDescriptor
  62.129 +            = parentFolder.defaultDestructiveActionIsArchive
  62.130 +                ? .archive
  62.131 +                : .trash
  62.132 +
  62.133 +        return folderIsOutbox(parentFolder) ? .trash : defaultDestructiveAction
  62.134 +    }
  62.135 +
  62.136 +    /// - returns: action to trigger if user clicks "flag" button
  62.137 +    public func getFlagAction(forMessageAt index: Int) -> SwipeActionDescriptor? {
  62.138 +        let parentFolder = getParentFolder(forMessageAt: index)
  62.139 +        if folderIsDraftsOrOutbox(parentFolder) {
  62.140 +            return nil
  62.141 +        } else {
  62.142 +            let flagged = messageQueryResults[index].imapFlags.flagged
  62.143 +            return flagged ? .unflag : .flag
  62.144 +        }
  62.145 +    }
  62.146 +
  62.147 +    /// - returns: action to trigger if user clicks "more" button
  62.148 +    public func getMoreAction(forMessageAt index: Int) -> SwipeActionDescriptor? {
  62.149 +        let parentFolder = getParentFolder(forMessageAt: index)
  62.150 +        if folderIsDraftsOrOutbox(parentFolder) {
  62.151 +            return nil
  62.152 +        } else {
  62.153 +            return .more
  62.154 +        }
  62.155 +    }
  62.156 +
  62.157 +    /// Whether or not to show LoginView
  62.158 +    public var showLoginView: Bool {
  62.159 +        return Account.all().isEmpty
  62.160 +    }
  62.161 +
  62.162 +    public func isReplyAllPossible(forRowAt indexPath: IndexPath) -> Bool {
  62.163 +        guard
  62.164 +            let replyAllPossible = replyAllPossibleChecker(forItemAt: indexPath)?.isReplyAllPossible()
  62.165 +            else {
  62.166 +                Log.shared.errorAndCrash("Invalid state")
  62.167 +                return false
  62.168 +        }
  62.169 +        return replyAllPossible
  62.170 +    }
  62.171 +
  62.172 +    /// Marks the message represented by the given `indexPaths` as flagged.
  62.173 +    /// - Parameter indexPath: indexPaths of messages to set flagged.
  62.174 +    public func markAsFlagged(indexPaths: [IndexPath]) {
  62.175 +        setFlaggedValue(forIndexPath: indexPaths, newValue: true)
  62.176 +    }
  62.177 +
  62.178 +    /// Marks the message represented by the given `indexPaths` as not-flagged.
  62.179 +    /// - Parameter indexPath: indexPaths of messages to unsset flag flag for.
  62.180 +    public func markAsUnFlagged(indexPaths: [IndexPath]) {
  62.181 +        setFlaggedValue(forIndexPath: indexPaths, newValue: false)
  62.182 +    }
  62.183 +
  62.184 +    /// Marks the message represented by the given `indexPaths` as seen.
  62.185 +    /// - Parameter indexPath: indexPaths of messages to set seen.
  62.186 +    public func markAsRead(indexPaths: [IndexPath]) {
  62.187 +        setSeenValue(forIndexPath: indexPaths, newValue: true)
  62.188 +    }
  62.189 +
  62.190 +    /// Marks the message represented by the given `indexPaths` as not-seen.
  62.191 +    /// - Parameter indexPath: indexPaths of messages to unsset seen flag for.
  62.192 +    public func markAsUnread(indexPaths: [IndexPath]) {
  62.193 +        setSeenValue(forIndexPath: indexPaths, newValue: false)
  62.194 +    }
  62.195 +
  62.196 +    /// Handles destructive button click for messages represented by given `indexPaths`.
  62.197 +    /// - Parameter indexPath: indexPathsdo handle destruktive action for
  62.198 +    public func handleUserClickedDestruktiveButton(forRowsAt indexPaths: [IndexPath]) {
  62.199 +        let messages = indexPaths.map { messageQueryResults[$0.row] }
  62.200 +        delete(messages: messages)
  62.201 +    }
  62.202 +
  62.203 +    private func messages(representedBy indexPaths: [IndexPath]) -> [Message?] {
  62.204 +        var messages : [Message?] = []
  62.205 +        indexPaths.forEach { (ip) in
  62.206 +            messages.append(self.message(representedByRowAt: ip))
  62.207 +        }
  62.208 +        return messages
  62.209 +    }
  62.210 +
  62.211 +    func delete(forIndexPath indexPath: IndexPath) {
  62.212 +        deleteMessages(at: [indexPath])
  62.213 +    }
  62.214 +
  62.215 +     /// Call in case of out-of-memory alert
  62.216 +    func freeMemory() {
  62.217 +        contactImageTool.clearCache()
  62.218 +    }
  62.219 +
  62.220 +    // MARK: - EmailDisplayViewModelDelegate Overrides
  62.221 +
  62.222 +    override func getMoveToFolderViewModel(forSelectedMessages: [IndexPath])
  62.223 +        -> MoveToAccountViewModel? {
  62.224 +            if let msgs = messages(representedBy: forSelectedMessages) as? [Message] {
  62.225 +                return MoveToAccountViewModel(messages: msgs)
  62.226 +            }
  62.227 +            return nil
  62.228 +    }
  62.229 +
  62.230 +    // MARK: - Fetch Older Messages
  62.231 +
  62.232 +    /// The number of rows (not yet displayed to the user) before we want to fetch older messages.
  62.233 +    /// A balance between good user experience (have data in time,
  62.234 +    /// ideally before the user has scrolled to the last row) and memory usage has to be found.
  62.235 +    private let numRowsBeforeLastToTriggerFetchOder = 1
  62.236 +
  62.237 +    /// Figures out whether or not fetching of older messages should be requested.
  62.238 +    /// Takes numRowsBeforeLastToTriggerFetchOder into account,
  62.239 +    ///
  62.240 +    /// - Parameter row: number of displayed tableView row to base computation on
  62.241 +    /// - Returns: true if fetch older messages should be requested, false otherwize
  62.242 +    private func triggerFetchOlder(lastDisplayedRow row: Int) -> Bool {
  62.243 +        return row >= rowCount - numRowsBeforeLastToTriggerFetchOder
  62.244 +    }
  62.245 +
  62.246 +    // When the user has scrolled down (almost) to the end, we fetch older emails.
  62.247 +    /// - Parameter indexPath: indexpath to pontetionally fetch older messages for
  62.248 +    public func fetchOlderMessagesIfRequired(forIndexPath indexPath: IndexPath) {
  62.249 +        if !triggerFetchOlder(lastDisplayedRow: indexPath.row) {
  62.250 +            return
  62.251 +        }
  62.252 +        folderToShow.fetchOlder(completion: nil)
  62.253 +    }
  62.254 +
  62.255 +    // MARK: - FetchNewMessages
  62.256 +
  62.257 +    public func fetchNewMessages(completition: (() -> Void)? = nil) {
  62.258 +        folderToShow.fetchNewMessages() {
  62.259 +            completition?()
  62.260 +        }
  62.261 +    }
  62.262 +
  62.263 +    // MARK: - multiple message selection handler
  62.264 +
  62.265 +    private var unreadMessages = false
  62.266 +    private var flaggedMessages = false
  62.267 +
  62.268 +
  62.269 +    /// Handles changes of the selected messages in edit mode.
  62.270 +    /// Updates toolbar buttons (maybe more)  accoring to selection.
  62.271 +    public func handleEditModeSelectionChange(selectedIndexPaths: [IndexPath]) {
  62.272 +        checkUnreadMessages(indexPaths: selectedIndexPaths)
  62.273 +        checkFlaggedMessages(indexPaths: selectedIndexPaths)
  62.274 +        guard let delegate = delegate as? EmailListViewModelDelegate else {
  62.275 +            Log.shared.errorAndCrash("No delegate")
  62.276 +            return
  62.277 +        }
  62.278 +        if selectedIndexPaths.count > 0 {
  62.279 +            delegate.setToolbarItemsEnabledState(to: true)
  62.280 +        } else {
  62.281 +            delegate.setToolbarItemsEnabledState(to: false)
  62.282 +        }
  62.283 +    }
  62.284 +
  62.285 +    private func checkFlaggedMessages(indexPaths: [IndexPath]) {
  62.286 +        let flagged = indexPaths.filter { (ip) -> Bool in
  62.287 +            if let flag = viewModel(for: ip.row)?.isFlagged {
  62.288 +                return flag
  62.289 +            }
  62.290 +            return false
  62.291 +        }
  62.292 +
  62.293 +        guard let delegate = delegate as? EmailListViewModelDelegate else {
  62.294 +            Log.shared.errorAndCrash("No delegate")
  62.295 +            return
  62.296 +        }
  62.297 +        if flagged.count == indexPaths.count {
  62.298 +            delegate.showUnflagButton(enabled: true)
  62.299 +        } else {
  62.300 +            delegate.showUnflagButton(enabled: false)
  62.301 +        }
  62.302 +    }
  62.303 +
  62.304 +    private func checkUnreadMessages(indexPaths: [IndexPath]) {
  62.305 +        let read = indexPaths.filter { (ip) -> Bool in
  62.306 +            if let read = viewModel(for: ip.row)?.isSeen {
  62.307 +                return read
  62.308 +            }
  62.309 +            return false
  62.310 +        }
  62.311 +
  62.312 +        guard let delegate = delegate as? EmailListViewModelDelegate else {
  62.313 +            Log.shared.errorAndCrash("No delegate")
  62.314 +            return
  62.315 +        }
  62.316 +        if read.count == indexPaths.count {
  62.317 +            delegate.showUnreadButton(enabled: true)
  62.318 +        } else {
  62.319 +            delegate.showUnreadButton(enabled: false)
  62.320 +        }
  62.321 +    }
  62.322 +}
  62.323 +
  62.324 +// MARK: - Filter & Search
  62.325 +
  62.326 +extension EmailListViewModel {
  62.327 +
  62.328 +    /// Call whenever the term to search for changes.
  62.329 +    /// - Parameter newSearchTerm: updated search term
  62.330 +    public func handleSearchTermChange(newSearchTerm: String) {
  62.331 +        if newSearchTerm == lastSearchTerm {
  62.332 +            // Happens e.g. when initially setting the cursor in search bar.
  62.333 +            return
  62.334 +        }
  62.335 +        lastSearchTerm = newSearchTerm
  62.336 +
  62.337 +        let search = newSearchTerm == "" ? nil : MessageQueryResultsSearch(searchTerm: lastSearchTerm)
  62.338 +        setNewSearchAndReload(search: search)
  62.339 +    }
  62.340 +
  62.341 +    /// Handles dissapearance of a SearchController
  62.342 +    public func handleSearchControllerDidDisappear() {
  62.343 +        setNewSearchAndReload(search: nil)
  62.344 +    }
  62.345 +
  62.346 +    private func handleFilterEnabledStateChange() {
  62.347 +        if isFilterEnabled {
  62.348 +            setNewFilterAndReload(filter: currentFilter)
  62.349 +        } else {
  62.350 +            setNewFilterAndReload(filter: nil)
  62.351 +        }
  62.352 +    }
  62.353 +
  62.354 +    private func setNewSearchAndReload(search: MessageQueryResultsSearch?) {
  62.355 +        resetQueryResultsAndReload(with: messageQueryResults.filter, search: search)
  62.356 +    }
  62.357 +
  62.358 +    private func setNewFilterAndReload(filter: MessageQueryResultsFilter?) {
  62.359 +        if let newFilter = filter {
  62.360 +            currentFilter = newFilter
  62.361 +        }
  62.362 +        resetQueryResultsAndReload(with: filter, search: messageQueryResults.search)
  62.363 +    }
  62.364 +
  62.365 +    // Every time filter or search changes, we have to rest QueryResults
  62.366 +    private func resetQueryResultsAndReload(with filter: MessageQueryResultsFilter? = nil,
  62.367 +                                            search: MessageQueryResultsSearch? = nil) {
  62.368 +        defer { informDelegateToReloadData() }
  62.369 +        messageQueryResults = MessageQueryResults(withFolder: folderToShow,
  62.370 +                                                  filter: filter,
  62.371 +                                                  search: search,
  62.372 +                                                  rowDelegate: self)
  62.373 +        do {
  62.374 +            try messageQueryResults.startMonitoring()
  62.375 +            try emailDetailViewModel?.replaceMessageQueryResults(with: messageQueryResults)
  62.376 +        } catch {
  62.377 +            Log.shared.errorAndCrash("Failed to start QRC   ")
  62.378 +            return
  62.379 +        }
  62.380 +    }
  62.381 +}
  62.382 +
  62.383 +// MARK: - Private
  62.384 +
  62.385 +extension EmailListViewModel {
  62.386 +
  62.387 +    private func setFlaggedValue(forIndexPath indexPath: [IndexPath], newValue flagged: Bool) {
  62.388 +        updatesEnabled = false
  62.389 +        let messages = indexPath.map { messageQueryResults[$0.row] }
  62.390 +        Message.setFlaggedValue(to: messages, newValue: flagged)
  62.391 +    }
  62.392 +
  62.393 +    private func setSeenValue(forIndexPath indexPath: [IndexPath], newValue seen: Bool) {
  62.394 +        let messages = indexPath.map { messageQueryResults[$0.row] }
  62.395 +        Message.setSeenValue(to: messages, newValue: seen)
  62.396 +    }
  62.397 +
  62.398 +    @discardableResult private func deleteMessages(at indexPath: [IndexPath]) -> [Message]? {
  62.399 +        let messages = indexPath.map { messageQueryResults[$0.row] }
  62.400 +        delete(messages: messages)
  62.401 +        return messages
  62.402 +    }
  62.403 +}
  62.404 +
  62.405 +// MARK: - Destination View Controller VM-Factory
  62.406 +
  62.407 +extension EmailListViewModel {
  62.408 +
  62.409 +    /// Destination View Controller's VM Factory
  62.410 +    /// - returns:  ComposeViewModel  with default configuration (for a new email).
  62.411 +    public func composeViewModelForNewMessage() -> ComposeViewModel {
  62.412 +        // Determine the sender.
  62.413 +        var someUser: Identity? = nil
  62.414 +        if let f = folderToShow as? RealFolderProtocol {
  62.415 +            someUser = f.account.user
  62.416 +        } else {
  62.417 +            let account = Account.defaultAccount()
  62.418 +            return ComposeViewModel(composeMode: .normal,
  62.419 +                                    prefilledFrom: account?.user)
  62.420 +        }
  62.421 +        let composeVM = ComposeViewModel(prefilledFrom: someUser)
  62.422 +        return composeVM
  62.423 +    }
  62.424 +
  62.425 +    /// Destination VM Factory - EmailDetail VM
  62.426 +    /// - returns:  EmailDetailViewModel with default configuration.
  62.427 +    public func emailDetialViewModel() -> EmailDetailViewModel {
  62.428 +        let detailQueryResults = messageQueryResults.clone()
  62.429 +        let createe = EmailDetailViewModel(messageQueryResults: detailQueryResults)
  62.430 +        createe.selectionChangeDelegate = self
  62.431 +        detailQueryResults.rowDelegate = createe
  62.432 +        emailDetailViewModel = createe
  62.433 +
  62.434 +        return createe
  62.435 +    }
  62.436 +}
  62.437 +
  62.438 +// MARK: - FilterViewDelegate
  62.439 +
  62.440 +extension EmailListViewModel: FilterViewDelegate {
  62.441 +
  62.442 +    func filterChanged(newFilter: MessageQueryResultsFilter) {
  62.443 +        setNewFilterAndReload(filter: newFilter)
  62.444 +    }
  62.445 +}
  62.446 +
  62.447 +// MARK: - QueryResultsIndexPathRowDelegate
  62.448 +
  62.449 +extension EmailListViewModel: QueryResultsIndexPathRowDelegate {
  62.450 +
  62.451 +    func didInsertRow(indexPath: IndexPath) {
  62.452 +        if updatesEnabled {
  62.453 +            delegate?.emailListViewModel(viewModel: self, didInsertDataAt: [indexPath])
  62.454 +        }
  62.455 +    }
  62.456 +
  62.457 +    func didUpdateRow(indexPath: IndexPath) {
  62.458 +        if updatesEnabled {
  62.459 +            delegate?.emailListViewModel(viewModel: self, didUpdateDataAt: [indexPath])
  62.460 +        }
  62.461 +    }
  62.462 +
  62.463 +    func didDeleteRow(indexPath: IndexPath) {
  62.464 +        delegate?.emailListViewModel(viewModel: self, didRemoveDataAt: [indexPath])
  62.465 +    }
  62.466 +
  62.467 +    func didMoveRow(from: IndexPath, to: IndexPath) {
  62.468 +        if updatesEnabled {
  62.469 +            delegate?.emailListViewModel(viewModel: self, didMoveData: from, toIndexPath: to)
  62.470 +        }
  62.471 +    }
  62.472 +
  62.473 +    func willChangeResults() {
  62.474 +        if updatesEnabled {
  62.475 +            delegate?.willReceiveUpdates(viewModel: self)
  62.476 +        }
  62.477 +    }
  62.478 +
  62.479 +    func didChangeResults() {
  62.480 +        if updatesEnabled {
  62.481 +            delegate?.allUpdatesReceived(viewModel: self)
  62.482 +        } else {
  62.483 +            updatesEnabled = true
  62.484 +        }
  62.485 +    }
  62.486 +}
  62.487 +
  62.488 +// MARK: - EmailDetailViewModelSelectionChangeDelegate
  62.489 +
  62.490 +extension EmailListViewModel: EmailDetailViewModelSelectionChangeDelegate {
  62.491 +
  62.492 +    func emailDetailViewModel(emailDetailViewModel: EmailDetailViewModel,
  62.493 +                              didSelectItemAt indexPath: IndexPath) {
  62.494 +        guard let del = delegate as? EmailListViewModelDelegate else {
  62.495 +            Log.shared.errorAndCrash("Wrong Delegate")
  62.496 +            return
  62.497 +        }
  62.498 +        del.select(itemAt: indexPath)
  62.499 +    }
  62.500 +}
    63.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    63.2 +++ b/pEpForiOS/UI/EmailDisplay/EmailDisplayList/MessageViewModel.swift	Fri Feb 07 12:31:01 2020 +0100
    63.3 @@ -0,0 +1,351 @@
    63.4 +//
    63.5 +//  MessageViewModel.swift
    63.6 +//  pEp
    63.7 +//
    63.8 +//  Created by Borja González de Pablo on 13/06/2018.
    63.9 +//  Copyright © 2018 p≡p Security S.A. All rights reserved.
   63.10 +//
   63.11 +
   63.12 +import Foundation
   63.13 +
   63.14 +import MessageModel
   63.15 +import pEpIOSToolbox
   63.16 +import PEPObjCAdapterFramework
   63.17 +
   63.18 +class MessageViewModel: CustomDebugStringConvertible {
   63.19 +    static fileprivate var maxBodyPreviewCharacters = 120
   63.20 +
   63.21 +    private let queueForHeavyStuff: OperationQueue = {
   63.22 +        let createe = OperationQueue()
   63.23 +        createe.qualityOfService = .userInitiated
   63.24 +        createe.name = "security.pep.MessageViewModel.queueForHeavyStuff"
   63.25 +        return createe
   63.26 +    }()
   63.27 +
   63.28 +    let message: Message
   63.29 +
   63.30 +    let uid: Int
   63.31 +    private let uuid: MessageID
   63.32 +    private let parentFolderName: String
   63.33 +    private let accountAddress: String
   63.34 +    private let displayedImageIdentity: Identity
   63.35 +
   63.36 +    let identity:Identity
   63.37 +    let dateSent: Date
   63.38 +    let longMessageFormatted: String?
   63.39 +    var senderContactImage: UIImage?
   63.40 +    private var ratingImage: UIImage?
   63.41 +    var showAttchmentIcon: Bool = false
   63.42 +    let from: String
   63.43 +    let subject: String
   63.44 +    var isFlagged: Bool = false
   63.45 +    var isSeen: Bool = false
   63.46 +    var dateText: String
   63.47 +    var profilePictureComposer: ProfilePictureComposerProtocol
   63.48 +    var body: NSAttributedString {
   63.49 +            return getBodyMessage()
   63.50 +    }
   63.51 +    var displayedUsername: String
   63.52 +    var internalBoddyPeek: String? = nil
   63.53 +    private var bodyPeek: String? {
   63.54 +        didSet {
   63.55 +            informIfBodyPeekCompleted()
   63.56 +        }
   63.57 +    }
   63.58 +    var bodyPeekCompletion: ((String) -> ())? = nil {
   63.59 +        didSet {
   63.60 +            guard bodyPeekCompletion != nil else {
   63.61 +                return
   63.62 +            }
   63.63 +            informIfBodyPeekCompleted()
   63.64 +        }
   63.65 +    }
   63.66 +
   63.67 +    required init(with message: Message) {
   63.68 +        self.message = message
   63.69 +
   63.70 +        uid = message.uid
   63.71 +        uuid = message.uuid
   63.72 +        parentFolderName = message.parent.name
   63.73 +        accountAddress = message.parent.account.user.address
   63.74 +
   63.75 +        longMessageFormatted = message.longMessageFormatted
   63.76 +        dateSent = message.sent ?? Date()
   63.77 +
   63.78 +        showAttchmentIcon = message.viewableAttachments().count > 0
   63.79 +        identity = (message.from ?? Identity(address: "unknown@unknown.com"))
   63.80 +        from = (message.from ?? Identity(address: "unknown@unknown.com")).userNameOrAddress
   63.81 +        displayedImageIdentity =  MessageViewModel.identityForImage(from: message)
   63.82 +        subject = message.shortMessage ?? ""
   63.83 +        isFlagged = message.imapFlags.flagged
   63.84 +        isSeen = message.imapFlags.seen
   63.85 +        dateText =  (message.sent ?? Date()).smartString()
   63.86 +        profilePictureComposer = PepProfilePictureComposer()
   63.87 +        displayedUsername = MessageViewModel.getDisplayedUsername(for: message)
   63.88 +        setBodyPeek(for: message)
   63.89 +    }
   63.90 +
   63.91 +    static private func getDisplayedUsername(for message: Message) -> String {
   63.92 +        if (message.parent.folderType == .sent
   63.93 +            || message.parent.folderType == .drafts){
   63.94 +            var identities: [String] = []
   63.95 +            message.allRecipients.forEach { (recepient) in
   63.96 +                let recepient = recepient.userNameOrAddress
   63.97 +                identities.append(recepient)
   63.98 +            }
   63.99 +            return identities.joined(separator: ", ")
  63.100 +        } else {
  63.101 +            return message.from?.userNameOrAddress ?? ""
  63.102 +
  63.103 +        }
  63.104 +    }
  63.105 +
  63.106 +    public func flagsDiffer(from messageViewModel: MessageViewModel) -> Bool {
  63.107 +        if self != messageViewModel {
  63.108 +            return true
  63.109 +        }
  63.110 +        return self.isFlagged != messageViewModel.isFlagged || self.isSeen != messageViewModel.isSeen
  63.111 +    }
  63.112 +
  63.113 +    func unsubscribeForUpdates() {
  63.114 +        queueForHeavyStuff.cancelAllOperations()
  63.115 +    }
  63.116 +
  63.117 +    private func setBodyPeek(for message: Message) {
  63.118 +        if let bodyPeek = internalBoddyPeek {
  63.119 +            self.bodyPeek = bodyPeek
  63.120 +        } else {
  63.121 +            let operation = getBodyPeekOperation(for: message) { [weak self] bodyPeek in
  63.122 +                // It's valid to loose self here. The view can dissappear @ any time.
  63.123 +                self?.bodyPeek = bodyPeek
  63.124 +            }
  63.125 +            queueForHeavyStuff.addOperation(operation)
  63.126 +        }
  63.127 +    }
  63.128 +
  63.129 +    private func informIfBodyPeekCompleted() {
  63.130 +        guard let bodyPeek = bodyPeek else {
  63.131 +            return
  63.132 +        }
  63.133 +        bodyPeekCompletion?(bodyPeek)
  63.134 +        bodyPeekCompletion = nil
  63.135 +    }
  63.136 +
  63.137 +    // Message threading is not supported. Let's keep it for now. It might be helpful for
  63.138 +    // reimplementing.
  63.139 +//    var internalMessageCount: Int? = nil
  63.140 +//    func messageCount(completion: @escaping (Int)->()) {
  63.141 +//        if let messageCount = internalMessageCount {
  63.142 +//            completion(messageCount)
  63.143 +//        } else {
  63.144 +//            let operation =  getMessageCountOperation { count in
  63.145 +//                completion(count)
  63.146 +//            }
  63.147 +//            if(!operation.isFinished){
  63.148 +//                addToRunningOperations(operation)
  63.149 +//            }
  63.150 +//        }
  63.151 +//    }
  63.152 +
  63.153 +    private class func identityForImage(from message: Message) -> Identity {
  63.154 +        switch message.parent.folderType {
  63.155 +        case .all, .archive, .spam, .trash, .flagged, .inbox, .normal, .pEpSync:
  63.156 +            return (message.from ?? Identity(address: "unknown@unknown.com"))
  63.157 +        case .drafts, .sent, .outbox:
  63.158 +            return message.to.first ?? Identity(address: "unknown@unknown.com")
  63.159 +        }
  63.160 +    }
  63.161 +
  63.162 +    class func getSummary(fromMessage msg: Message) -> String {