merge default IOS-1758
authorbuff <andreas@pep-project.org>
Tue, 20 Aug 2019 10:02:18 +0200
branchIOS-1758
changeset 971643f382b2e130
parent 9696 b8419419ecd9
parent 9699 45d4a12fdb83
child 9727 36be231969e5
merge default
     1.1 --- a/pEpForiOS.xcodeproj/project.pbxproj	Fri Aug 16 14:15:14 2019 +0200
     1.2 +++ b/pEpForiOS.xcodeproj/project.pbxproj	Tue Aug 20 10:02:18 2019 +0200
     1.3 @@ -205,6 +205,11 @@
     1.4  		220DCE371E0AB5CC002FE716 /* MessageSubjectCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 220DCE331E0AB5CC002FE716 /* MessageSubjectCell.swift */; };
     1.5  		222B35581DF96389007A1F82 /* Capability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 222B35571DF96389007A1F82 /* Capability.swift */; };
     1.6  		228038681DC9DE6D00F1CB45 /* TextfieldResponder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 228038671DC9DE6D00F1CB45 /* TextfieldResponder.swift */; };
     1.7 +		3705095D22CF4AC900CB73D6 /* KeySyncHandshakeViewModelTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705095C22CF4AC900CB73D6 /* KeySyncHandshakeViewModelTest.swift */; };
     1.8 +		3705096622CF688F00CB73D6 /* KeySyncHandshakeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705096522CF688F00CB73D6 /* KeySyncHandshakeViewModel.swift */; };
     1.9 +		3705096822CF6AD100CB73D6 /* KeySyncHandshakeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705096722CF6AD100CB73D6 /* KeySyncHandshakeViewController.swift */; };
    1.10 +		3705096A22D4D83B00CB73D6 /* PEPSessionMoc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705096922D4D83B00CB73D6 /* PEPSessionMoc.swift */; };
    1.11 +		3705096C22DC8C1800CB73D6 /* KeyInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705096B22DC8C1800CB73D6 /* KeyInputView.swift */; };
    1.12  		3705703B22B7C793002E3AAD /* ActionCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705703A22B7C793002E3AAD /* ActionCellViewModel.swift */; };
    1.13  		3705703F22B8E3B9002E3AAD /* ActionCellViewModelTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705703E22B8E3B9002E3AAD /* ActionCellViewModelTest.swift */; };
    1.14  		3705704122B8EB27002E3AAD /* KeySyncDeviceGroupServiceMoc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705704022B8EB27002E3AAD /* KeySyncDeviceGroupServiceMoc.swift */; };
    1.15 @@ -678,6 +683,11 @@
    1.16  		220DCE331E0AB5CC002FE716 /* MessageSubjectCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageSubjectCell.swift; sourceTree = "<group>"; };
    1.17  		222B35571DF96389007A1F82 /* Capability.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Capability.swift; sourceTree = "<group>"; };
    1.18  		228038671DC9DE6D00F1CB45 /* TextfieldResponder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextfieldResponder.swift; sourceTree = "<group>"; };
    1.19 +		3705095C22CF4AC900CB73D6 /* KeySyncHandshakeViewModelTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeySyncHandshakeViewModelTest.swift; sourceTree = "<group>"; };
    1.20 +		3705096522CF688F00CB73D6 /* KeySyncHandshakeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeySyncHandshakeViewModel.swift; sourceTree = "<group>"; };
    1.21 +		3705096722CF6AD100CB73D6 /* KeySyncHandshakeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeySyncHandshakeViewController.swift; sourceTree = "<group>"; };
    1.22 +		3705096922D4D83B00CB73D6 /* PEPSessionMoc.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PEPSessionMoc.swift; sourceTree = "<group>"; };
    1.23 +		3705096B22DC8C1800CB73D6 /* KeyInputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyInputView.swift; sourceTree = "<group>"; };
    1.24  		3705703A22B7C793002E3AAD /* ActionCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionCellViewModel.swift; sourceTree = "<group>"; };
    1.25  		3705703E22B8E3B9002E3AAD /* ActionCellViewModelTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionCellViewModelTest.swift; sourceTree = "<group>"; };
    1.26  		3705704022B8EB27002E3AAD /* KeySyncDeviceGroupServiceMoc.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeySyncDeviceGroupServiceMoc.swift; sourceTree = "<group>"; };
    1.27 @@ -1033,6 +1043,7 @@
    1.28  		150707DD21006D0200AA213F /* UI */ = {
    1.29  			isa = PBXGroup;
    1.30  			children = (
    1.31 +				3705095B22CF465300CB73D6 /* KeySyncHandshake */,
    1.32  				15D4399D216F703100EB3933 /* Compose */,
    1.33  				4356FFEA21356CB600804089 /* Util */,
    1.34  			);
    1.35 @@ -1596,6 +1607,24 @@
    1.36  			name = Cells;
    1.37  			sourceTree = "<group>";
    1.38  		};
    1.39 +		3705095B22CF465300CB73D6 /* KeySyncHandshake */ = {
    1.40 +			isa = PBXGroup;
    1.41 +			children = (
    1.42 +				3705095C22CF4AC900CB73D6 /* KeySyncHandshakeViewModelTest.swift */,
    1.43 +				3705096922D4D83B00CB73D6 /* PEPSessionMoc.swift */,
    1.44 +			);
    1.45 +			path = KeySyncHandshake;
    1.46 +			sourceTree = "<group>";
    1.47 +		};
    1.48 +		3705096422CF686C00CB73D6 /* KeySyncHandshake */ = {
    1.49 +			isa = PBXGroup;
    1.50 +			children = (
    1.51 +				3705096522CF688F00CB73D6 /* KeySyncHandshakeViewModel.swift */,
    1.52 +				3705096722CF6AD100CB73D6 /* KeySyncHandshakeViewController.swift */,
    1.53 +			);
    1.54 +			path = KeySyncHandshake;
    1.55 +			sourceTree = "<group>";
    1.56 +		};
    1.57  		4304FCFD1EBB8C2C0086DADA /* LanguageList */ = {
    1.58  			isa = PBXGroup;
    1.59  			children = (
    1.60 @@ -1945,6 +1974,7 @@
    1.61  				152A39932190587100D9F8E4 /* TextViewInTableViewScrollUtil.swift */,
    1.62  				B7DFEA51225368670080A2BA /* VirtualFolder.swift */,
    1.63  				B7DFEA5322536D5E0080A2BA /* UnifiedInbox.swift */,
    1.64 +				3705096B22DC8C1800CB73D6 /* KeyInputView.swift */,
    1.65  			);
    1.66  			path = Util;
    1.67  			sourceTree = "<group>";
    1.68 @@ -2046,23 +2076,24 @@
    1.69  		43ED53611CC77F95006AB156 /* UI */ = {
    1.70  			isa = PBXGroup;
    1.71  			children = (
    1.72 -				B706C0EF1EA8C378006B2F6C /* StoryboardFiles */,
    1.73 -				432E80FA2191AF5100359879 /* Fonts */,
    1.74 -				43AA82511E9B925000ABD5A8 /* Util */,
    1.75 -				003C0FAA20B57C2E0093A987 /* SplitView */,
    1.76 -				15BA537A20A1F5CA0090F126 /* MoveToFolder */,
    1.77 +				43A6E0491E5726C8005BEE69 /* Background */,
    1.78  				15265942216230B0006A78DF /* Compose */,
    1.79 +				15FE1F741FE122B200CC2D97 /* Credits */,
    1.80  				B70D32B0205BCFBD0094A92A /* EmailDisplay */,
    1.81  				43ED53621CC77F95006AB156 /* EmailDisplayList */,
    1.82 +				B78CF8261E76D70D008C1739 /* Filter */,
    1.83 +				B71EBBB41E55E43100150177 /* Folder */,
    1.84 +				432E80FA2191AF5100359879 /* Fonts */,
    1.85 +				438D5A6F1EA77CFC001A37E1 /* Handshake */,
    1.86 +				3705096422CF686C00CB73D6 /* KeySyncHandshake */,
    1.87 +				B70D32AA205BCCC70094A92A /* Login */,
    1.88 +				B70D32AF205BCF460094A92A /* ManualLogin */,
    1.89 +				15BA537A20A1F5CA0090F126 /* MoveToFolder */,
    1.90 +				15874BA72127493E00A3A4A6 /* Settings */,
    1.91 +				003C0FAA20B57C2E0093A987 /* SplitView */,
    1.92 +				B706C0EF1EA8C378006B2F6C /* StoryboardFiles */,
    1.93  				492EF92B20C69547004EAE14 /* Thread */,
    1.94 -				B70D32AA205BCCC70094A92A /* Login */,
    1.95 -				15FE1F741FE122B200CC2D97 /* Credits */,
    1.96 -				B78CF8261E76D70D008C1739 /* Filter */,
    1.97 -				43A6E0491E5726C8005BEE69 /* Background */,
    1.98 -				B71EBBB41E55E43100150177 /* Folder */,
    1.99 -				15874BA72127493E00A3A4A6 /* Settings */,
   1.100 -				B70D32AF205BCF460094A92A /* ManualLogin */,
   1.101 -				438D5A6F1EA77CFC001A37E1 /* Handshake */,
   1.102 +				43AA82511E9B925000ABD5A8 /* Util */,
   1.103  			);
   1.104  			path = UI;
   1.105  			sourceTree = "<group>";
   1.106 @@ -2900,6 +2931,7 @@
   1.107  				15874BD421274BD400A3A4A6 /* TrustedServerSettingCell.swift in Sources */,
   1.108  				A1014DA71D1173CD00C472A8 /* UIHelper.swift in Sources */,
   1.109  				43A6E0581E57400E005BEE69 /* RatingReEvaluator.swift in Sources */,
   1.110 +				3705096622CF688F00CB73D6 /* KeySyncHandshakeViewModel.swift in Sources */,
   1.111  				49C34AF620E4F649009D11CC /* CellDetailTransition.swift in Sources */,
   1.112  				492EF92A20C18C6C004EAE14 /* DisplayedMessage.swift in Sources */,
   1.113  				49228A5520D4035100A51E9D /* DetailCellSegue.swift in Sources */,
   1.114 @@ -2908,6 +2940,7 @@
   1.115  				152A39CE21905C3E00D9F8E4 /* ComposeHelpers.swift in Sources */,
   1.116  				43985D0A2044296D0080FA9A /* OAuth2AuthViewModel.swift in Sources */,
   1.117  				49691B1520D7FD0200CA9367 /* MessageViewModelConfigurable.swift in Sources */,
   1.118 +				3705096822CF6AD100CB73D6 /* KeySyncHandshakeViewController.swift in Sources */,
   1.119  				152A39CF21905C3E00D9F8E4 /* ComposeUtil.swift in Sources */,
   1.120  				152A39C821905C3E00D9F8E4 /* ComposeViewModel+InitData.swift in Sources */,
   1.121  				0038494C20D2587F008000EA /* PepPictureComposer.swift in Sources */,
   1.122 @@ -2920,6 +2953,7 @@
   1.123  				43D0702F2133DB3F0013B120 /* AppSettings.swift in Sources */,
   1.124  				00FD0CE62101F7D700BA0C56 /* ScreenComposerProtocol.swift in Sources */,
   1.125  				3705703B22B7C793002E3AAD /* ActionCellViewModel.swift in Sources */,
   1.126 +				3705096C22DC8C1800CB73D6 /* KeyInputView.swift in Sources */,
   1.127  				4351C2D81F4441190053381F /* references.c in Sources */,
   1.128  				152A39DC21905C3E00D9F8E4 /* TextViewContainingTableViewCell.swift in Sources */,
   1.129  				000D3C2F20D12BFD006B11B2 /* MessageViewModel.swift in Sources */,
   1.130 @@ -3024,6 +3058,7 @@
   1.131  				15B483DB1F28E2FC000FB2CF /* SpecialUseMailboxesTest.swift in Sources */,
   1.132  				151F71FB202A06760057C74D /* MockBackgrounder.swift in Sources */,
   1.133  				43D51E891DD5D902008B77A8 /* SimpleOperationsTest.swift in Sources */,
   1.134 +				3705096A22D4D83B00CB73D6 /* PEPSessionMoc.swift in Sources */,
   1.135  				151F71FE202A06760057C74D /* CdMessage+TestUtils.swift in Sources */,
   1.136  				3791A45F22BA6A0300A9E534 /* MessageModelServiceMoc.swift in Sources */,
   1.137  				151F71F9202A06760057C74D /* ReplicationServiceObserver.swift in Sources */,
   1.138 @@ -3038,6 +3073,7 @@
   1.139  				150707DC21006CD000AA213F /* ComposeUtilTest.swift in Sources */,
   1.140  				15D439A5216F7E0E00EB3933 /* AccountPickerViewModelTest.swift in Sources */,
   1.141  				1574D07D2114696B00FEDC93 /* URL+MailToTest.swift in Sources */,
   1.142 +				3705095D22CF4AC900CB73D6 /* KeySyncHandshakeViewModelTest.swift in Sources */,
   1.143  				4356FFEC21356CB600804089 /* ReplyAllPossibleCheckerTest.swift in Sources */,
   1.144  				430C80E01D0EADC200CD4582 /* PepAdapterTests.swift in Sources */,
   1.145  				00DF2C3B2164C53F004EBA6C /* FolderViewModelTest.swift in Sources */,
     2.1 --- a/pEpForiOS/Base.lproj/Reusable.storyboard	Fri Aug 16 14:15:14 2019 +0200
     2.2 +++ b/pEpForiOS/Base.lproj/Reusable.storyboard	Tue Aug 20 10:02:18 2019 +0200
     2.3 @@ -101,7 +101,173 @@
     2.4                  </viewController>
     2.5                  <placeholder placeholderIdentifier="IBFirstResponder" id="TM4-zV-K5Y" userLabel="First Responder" sceneMemberID="firstResponder"/>
     2.6              </objects>
     2.7 -            <point key="canvasLocation" x="-879" y="-351"/>
     2.8 +            <point key="canvasLocation" x="-1065" y="-351"/>
     2.9 +        </scene>
    2.10 +        <!--Key Sync Handshake View Controller-->
    2.11 +        <scene sceneID="5ce-Hn-mnm">
    2.12 +            <objects>
    2.13 +                <viewController storyboardIdentifier="KeySyncHandshakeViewController" id="GZS-2u-rXb" customClass="KeySyncHandshakeViewController" customModule="pEpForiOS" customModuleProvider="target" sceneMemberID="viewController">
    2.14 +                    <view key="view" contentMode="scaleToFill" id="IdW-oi-ZvZ">
    2.15 +                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
    2.16 +                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
    2.17 +                        <subviews>
    2.18 +                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fiE-pm-mWd" customClass="KeyInputView" customModule="pEpForiOS" customModuleProvider="target">
    2.19 +                                <rect key="frame" x="57.5" y="135" width="260" height="417.5"/>
    2.20 +                                <subviews>
    2.21 +                                    <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="YMa-Kc-JoR">
    2.22 +                                        <rect key="frame" x="0.0" y="10" width="260" height="407.5"/>
    2.23 +                                        <subviews>
    2.24 +                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="htI-ge-ZQj">
    2.25 +                                                <rect key="frame" x="12" y="0.0" width="236" height="30"/>
    2.26 +                                                <subviews>
    2.27 +                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ckp-rp-1Pd">
    2.28 +                                                        <rect key="frame" x="96.5" y="4.5" width="43.5" height="20.5"/>
    2.29 +                                                        <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
    2.30 +                                                        <nil key="textColor"/>
    2.31 +                                                        <nil key="highlightedColor"/>
    2.32 +                                                    </label>
    2.33 +                                                    <button opaque="NO" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6fr-an-tAC">
    2.34 +                                                        <rect key="frame" x="206" y="0.0" width="30" height="30"/>
    2.35 +                                                        <constraints>
    2.36 +                                                            <constraint firstAttribute="width" secondItem="6fr-an-tAC" secondAttribute="height" multiplier="1:1" id="sB9-cU-tpx"/>
    2.37 +                                                        </constraints>
    2.38 +                                                        <inset key="imageEdgeInsets" minX="10" minY="5" maxX="0.0" maxY="5"/>
    2.39 +                                                        <state key="normal" title="Button" image="pEpForiOS-icon-languagechange"/>
    2.40 +                                                        <connections>
    2.41 +                                                            <action selector="didPress:" destination="GZS-2u-rXb" eventType="touchUpInside" id="XwJ-Yx-Fbk"/>
    2.42 +                                                        </connections>
    2.43 +                                                    </button>
    2.44 +                                                </subviews>
    2.45 +                                                <constraints>
    2.46 +                                                    <constraint firstItem="6fr-an-tAC" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="ckp-rp-1Pd" secondAttribute="trailing" constant="10" id="Ai3-EY-gkI"/>
    2.47 +                                                    <constraint firstItem="6fr-an-tAC" firstAttribute="centerY" secondItem="htI-ge-ZQj" secondAttribute="centerY" id="DKf-9K-sdJ"/>
    2.48 +                                                    <constraint firstItem="6fr-an-tAC" firstAttribute="height" secondItem="htI-ge-ZQj" secondAttribute="height" id="Svc-uO-nhy"/>
    2.49 +                                                    <constraint firstAttribute="trailing" secondItem="6fr-an-tAC" secondAttribute="trailing" id="WuB-Op-Eer"/>
    2.50 +                                                    <constraint firstAttribute="height" constant="30" id="aO3-QP-t0p"/>
    2.51 +                                                    <constraint firstItem="ckp-rp-1Pd" firstAttribute="centerX" secondItem="htI-ge-ZQj" secondAttribute="centerX" id="gaV-xz-tKz"/>
    2.52 +                                                    <constraint firstItem="ckp-rp-1Pd" firstAttribute="centerY" secondItem="htI-ge-ZQj" secondAttribute="centerY" id="wj5-ro-Hwx"/>
    2.53 +                                                </constraints>
    2.54 +                                            </view>
    2.55 +                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rPi-Px-Pyp">
    2.56 +                                                <rect key="frame" x="12" y="40" width="236" height="17"/>
    2.57 +                                                <fontDescription key="fontDescription" type="system" pointSize="14"/>
    2.58 +                                                <nil key="textColor"/>
    2.59 +                                                <nil key="highlightedColor"/>
    2.60 +                                            </label>
    2.61 +                                            <label opaque="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" minimumFontSize="7" translatesAutoresizingMaskIntoConstraints="NO" id="GC3-wG-GHD">
    2.62 +                                                <rect key="frame" x="12" y="67" width="236" height="284.5"/>
    2.63 +                                                <gestureRecognizers/>
    2.64 +                                                <string key="text">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.</string>
    2.65 +                                                <fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
    2.66 +                                                <nil key="textColor"/>
    2.67 +                                                <nil key="highlightedColor"/>
    2.68 +                                                <connections>
    2.69 +                                                    <outletCollection property="gestureRecognizers" destination="qFT-Cr-cyd" appends="YES" id="Qd8-tn-R83"/>
    2.70 +                                                </connections>
    2.71 +                                            </label>
    2.72 +                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="FhS-sc-rLm">
    2.73 +                                                <rect key="frame" x="0.0" y="361.5" width="260" height="46"/>
    2.74 +                                                <subviews>
    2.75 +                                                    <stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="1" translatesAutoresizingMaskIntoConstraints="NO" id="H3i-qp-hfc">
    2.76 +                                                        <rect key="frame" x="0.0" y="1" width="260" height="45"/>
    2.77 +                                                        <subviews>
    2.78 +                                                            <button opaque="NO" tag="2" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="emU-WV-Kap">
    2.79 +                                                                <rect key="frame" x="0.0" y="0.0" width="86" height="45"/>
    2.80 +                                                                <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="15"/>
    2.81 +                                                                <state key="normal" title="Button"/>
    2.82 +                                                                <connections>
    2.83 +                                                                    <action selector="didPress:" destination="GZS-2u-rXb" eventType="touchUpInside" id="Qh9-Xn-6Jk"/>
    2.84 +                                                                </connections>
    2.85 +                                                            </button>
    2.86 +                                                            <button opaque="NO" tag="3" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Rgh-E1-f1w">
    2.87 +                                                                <rect key="frame" x="87" y="0.0" width="86" height="45"/>
    2.88 +                                                                <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="15"/>
    2.89 +                                                                <state key="normal" title="Button"/>
    2.90 +                                                                <connections>
    2.91 +                                                                    <action selector="didPress:" destination="GZS-2u-rXb" eventType="touchUpInside" id="7oe-KK-94F"/>
    2.92 +                                                                </connections>
    2.93 +                                                            </button>
    2.94 +                                                            <button opaque="NO" tag="4" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="w5A-sP-MB2">
    2.95 +                                                                <rect key="frame" x="174" y="0.0" width="86" height="45"/>
    2.96 +                                                                <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="15"/>
    2.97 +                                                                <state key="normal" title="Button"/>
    2.98 +                                                                <connections>
    2.99 +                                                                    <action selector="didPress:" destination="GZS-2u-rXb" eventType="touchUpInside" id="cCN-kJ-4MM"/>
   2.100 +                                                                </connections>
   2.101 +                                                            </button>
   2.102 +                                                        </subviews>
   2.103 +                                                        <constraints>
   2.104 +                                                            <constraint firstAttribute="height" constant="45" id="T11-e3-GwM"/>
   2.105 +                                                        </constraints>
   2.106 +                                                    </stackView>
   2.107 +                                                </subviews>
   2.108 +                                                <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
   2.109 +                                                <constraints>
   2.110 +                                                    <constraint firstAttribute="bottom" secondItem="H3i-qp-hfc" secondAttribute="bottom" id="CgO-Nc-slt"/>
   2.111 +                                                    <constraint firstItem="H3i-qp-hfc" firstAttribute="leading" secondItem="FhS-sc-rLm" secondAttribute="leading" id="diT-6U-iIz"/>
   2.112 +                                                    <constraint firstAttribute="height" constant="46" id="it5-u7-ocl"/>
   2.113 +                                                    <constraint firstAttribute="trailing" secondItem="H3i-qp-hfc" secondAttribute="trailing" id="xoK-fB-cte"/>
   2.114 +                                                </constraints>
   2.115 +                                            </view>
   2.116 +                                        </subviews>
   2.117 +                                        <constraints>
   2.118 +                                            <constraint firstItem="htI-ge-ZQj" firstAttribute="leading" secondItem="YMa-Kc-JoR" secondAttribute="leading" constant="12" id="BcI-Ei-xIk"/>
   2.119 +                                            <constraint firstAttribute="trailing" secondItem="GC3-wG-GHD" secondAttribute="trailing" constant="12" id="Lxa-Jg-VAB"/>
   2.120 +                                            <constraint firstItem="GC3-wG-GHD" firstAttribute="leading" secondItem="YMa-Kc-JoR" secondAttribute="leading" constant="12" id="QeN-14-1s4"/>
   2.121 +                                            <constraint firstAttribute="trailing" secondItem="rPi-Px-Pyp" secondAttribute="trailing" constant="12" id="Te7-kU-Xea"/>
   2.122 +                                            <constraint firstAttribute="trailing" secondItem="FhS-sc-rLm" secondAttribute="trailing" id="UK3-Z6-QHQ"/>
   2.123 +                                            <constraint firstAttribute="trailing" secondItem="htI-ge-ZQj" secondAttribute="trailing" constant="12" id="Uu6-LM-wji"/>
   2.124 +                                            <constraint firstItem="FhS-sc-rLm" firstAttribute="leading" secondItem="YMa-Kc-JoR" secondAttribute="leading" id="fIH-2B-tWq"/>
   2.125 +                                            <constraint firstItem="rPi-Px-Pyp" firstAttribute="leading" secondItem="YMa-Kc-JoR" secondAttribute="leading" constant="12" id="w6P-ue-dqy"/>
   2.126 +                                        </constraints>
   2.127 +                                    </stackView>
   2.128 +                                </subviews>
   2.129 +                                <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
   2.130 +                                <constraints>
   2.131 +                                    <constraint firstItem="YMa-Kc-JoR" firstAttribute="leading" secondItem="fiE-pm-mWd" secondAttribute="leading" id="EAC-nr-iun"/>
   2.132 +                                    <constraint firstAttribute="width" constant="260" id="gIO-vA-Pn9"/>
   2.133 +                                    <constraint firstItem="YMa-Kc-JoR" firstAttribute="top" secondItem="fiE-pm-mWd" secondAttribute="top" constant="10" id="neq-VA-ZUu"/>
   2.134 +                                    <constraint firstAttribute="trailing" secondItem="YMa-Kc-JoR" secondAttribute="trailing" id="xBm-Xd-JL5"/>
   2.135 +                                    <constraint firstAttribute="bottom" secondItem="YMa-Kc-JoR" secondAttribute="bottom" id="xu3-OF-yp5"/>
   2.136 +                                </constraints>
   2.137 +                                <userDefinedRuntimeAttributes>
   2.138 +                                    <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
   2.139 +                                        <integer key="value" value="15"/>
   2.140 +                                    </userDefinedRuntimeAttribute>
   2.141 +                                    <userDefinedRuntimeAttribute type="boolean" keyPath="clipsToBounds" value="YES"/>
   2.142 +                                </userDefinedRuntimeAttributes>
   2.143 +                            </view>
   2.144 +                        </subviews>
   2.145 +                        <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.29999999999999999" colorSpace="custom" customColorSpace="sRGB"/>
   2.146 +                        <constraints>
   2.147 +                            <constraint firstItem="fiE-pm-mWd" firstAttribute="centerX" secondItem="O4B-B0-4XF" secondAttribute="centerX" id="48M-KR-Nr8"/>
   2.148 +                            <constraint firstItem="fiE-pm-mWd" firstAttribute="centerY" secondItem="O4B-B0-4XF" secondAttribute="centerY" id="OGZ-D8-d2h"/>
   2.149 +                            <constraint firstItem="O4B-B0-4XF" firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="fiE-pm-mWd" secondAttribute="bottom" constant="35" id="Qq0-YL-fDN"/>
   2.150 +                        </constraints>
   2.151 +                        <viewLayoutGuide key="safeArea" id="O4B-B0-4XF"/>
   2.152 +                    </view>
   2.153 +                    <connections>
   2.154 +                        <outlet property="accept" destination="w5A-sP-MB2" id="Lcb-sF-aRM"/>
   2.155 +                        <outlet property="alertTitle" destination="ckp-rp-1Pd" id="WIa-4m-pJy"/>
   2.156 +                        <outlet property="buttonsView" destination="FhS-sc-rLm" id="5Kd-Yz-Pub"/>
   2.157 +                        <outlet property="cancel" destination="emU-WV-Kap" id="DjI-VP-c4R"/>
   2.158 +                        <outlet property="contentView" destination="fiE-pm-mWd" id="eNm-5G-7Xa"/>
   2.159 +                        <outlet property="decline" destination="Rgh-E1-f1w" id="h3F-j9-O5m"/>
   2.160 +                        <outlet property="keySyncWords" destination="GC3-wG-GHD" id="D6t-PC-XAb"/>
   2.161 +                        <outlet property="message" destination="rPi-Px-Pyp" id="Pyb-o1-Nmp"/>
   2.162 +                    </connections>
   2.163 +                </viewController>
   2.164 +                <placeholder placeholderIdentifier="IBFirstResponder" id="rVu-Ti-LbX" userLabel="First Responder" sceneMemberID="firstResponder"/>
   2.165 +                <pongPressGestureRecognizer allowableMovement="10" minimumPressDuration="0.5" id="qFT-Cr-cyd">
   2.166 +                    <connections>
   2.167 +                        <action selector="didLongPressWords:" destination="GZS-2u-rXb" id="363-2M-vDw"/>
   2.168 +                    </connections>
   2.169 +                </pongPressGestureRecognizer>
   2.170 +            </objects>
   2.171 +            <point key="canvasLocation" x="-338.39999999999998" y="-345.87706146926541"/>
   2.172          </scene>
   2.173      </scenes>
   2.174 +    <resources>
   2.175 +        <image name="pEpForiOS-icon-languagechange" width="100" height="100"/>
   2.176 +    </resources>
   2.177  </document>
     3.1 --- a/pEpForiOS/KeySync/KeySyncHandshakeService.swift	Fri Aug 16 14:15:14 2019 +0200
     3.2 +++ b/pEpForiOS/KeySync/KeySyncHandshakeService.swift	Tue Aug 20 10:02:18 2019 +0200
     3.3 @@ -33,49 +33,23 @@
     3.4                  return
     3.5              }
     3.6  
     3.7 -            let lang = Locale.current.languageCode
     3.8 -            let trustwords = try! PEPSession().getTrustwordsFpr1(meFPR,
     3.9 -                                                                 fpr2: partnerFPR,
    3.10 -                                                                 language: lang,
    3.11 -                                                                 full: true)
    3.12 -
    3.13 -            // Show Handshake
    3.14 -            let newAlertView = UIAlertController.pEpAlertController(title: "Handshake",
    3.15 -                                                                    message: trustwords,
    3.16 -                                                                    preferredStyle: .alert)
    3.17 -            // Accept Action
    3.18 -            newAlertView.addAction(UIAlertAction(title: "Confirm Trustwords", style: .default) { action in
    3.19 -                completion?(PEPSyncHandshakeResult.accepted)
    3.20 -            })
    3.21 -
    3.22 -            // Reject Action
    3.23 -            newAlertView.addAction(UIAlertAction(title: "Wrong Trustwords", style: .destructive) { action in
    3.24 -                completion?(PEPSyncHandshakeResult.rejected)
    3.25 -            })
    3.26 -
    3.27 -            // Cancel Action
    3.28 -            newAlertView.addAction(UIAlertAction(title: "Cancel", style: .cancel) { action in
    3.29 -                completion?(PEPSyncHandshakeResult.cancel)
    3.30 -            })
    3.31 -            safeSelf.alertView = newAlertView
    3.32 -
    3.33 -            guard let vc = safeSelf.presenter else {
    3.34 +            guard let viewController = safeSelf.presenter else {
    3.35                  Log.shared.errorAndCrash("No Presenter")
    3.36                  return
    3.37              }
    3.38 -            vc.present(newAlertView, animated: true, completion: nil)
    3.39 +
    3.40 +            viewController.presentKeySyncHandShakeAlert(meFPR: meFPR, partnerFPR: partnerFPR)
    3.41 +            { action in
    3.42 +                switch action {
    3.43 +                case .accept:
    3.44 +                    completion?(PEPSyncHandshakeResult.accepted)
    3.45 +                case .cancel:
    3.46 +                    completion?(PEPSyncHandshakeResult.cancel)
    3.47 +                case .decline:
    3.48 +                    completion?(PEPSyncHandshakeResult.rejected)
    3.49 +                }
    3.50 +            }
    3.51          }
    3.52 -
    3.53 -        //        DispatchQueue.main.async { [weak self] in
    3.54 -        //            let session = Session()
    3.55 -        //            session.performAndWait {
    3.56 -        //                let meIdentity = Identity.newObject(onSession: session)
    3.57 -        //                meIdentity.fingerprint = me.fingerPrint
    3.58 -        //
    3.59 -        //                let partnerIdentity = Identity.newObject(onSession: session)
    3.60 -        //                partnerIdentity.fingerprint = partner.fingerPrint
    3.61 -        //            }
    3.62 -        //        }
    3.63      }
    3.64  
    3.65      //!!!: unimplemented stub
    3.66 @@ -85,12 +59,12 @@
    3.67      }
    3.68  
    3.69      func cancelHandshake() {
    3.70 -        DispatchQueue.main.async { [weak self] in
    3.71 -            guard let me = self else {
    3.72 -                Log.shared.errorAndCrash("Lost myself")
    3.73 +        guard let keySyncHandShakeAlert  =
    3.74 +            presenter?.presentedViewController as? KeySyncHandshakeViewController else {
    3.75                  return
    3.76 -            }
    3.77 -            me.alertView?.dismiss(animated: true)
    3.78 +        }
    3.79 +        DispatchQueue.main.async {
    3.80 +            keySyncHandShakeAlert.dismiss(animated: true)
    3.81          }
    3.82      }
    3.83  
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/pEpForiOS/UI/KeySyncHandshake/KeySyncHandshakeViewController.swift	Tue Aug 20 10:02:18 2019 +0200
     4.3 @@ -0,0 +1,176 @@
     4.4 +//
     4.5 +//  KeySyncHandshakeViewController.swift
     4.6 +//  pEp
     4.7 +//
     4.8 +//  Created by Alejandro Gelos on 05/07/2019.
     4.9 +//  Copyright © 2019 p≡p Security S.A. All rights reserved.
    4.10 +//
    4.11 +
    4.12 +import UIKit
    4.13 +
    4.14 +final class KeySyncHandshakeViewController: UIViewController {
    4.15 +    enum Action {
    4.16 +        case cancel, decline, accept
    4.17 +    }
    4.18 +
    4.19 +    static let storyboardId = "KeySyncHandshakeViewController"
    4.20 +    
    4.21 +    @IBOutlet weak var keySyncWords: UILabel! {
    4.22 +        didSet {
    4.23 +            keySyncWords.backgroundColor = .pEpLightBackground
    4.24 +            keySyncWords.layer.borderColor = UIColor.pEpGreyLines.cgColor
    4.25 +            keySyncWords.layer.cornerRadius = 3
    4.26 +            keySyncWords.layer.borderWidth = 1
    4.27 +        }
    4.28 +    }
    4.29 +    @IBOutlet weak var contentView: KeyInputView! {
    4.30 +        didSet {
    4.31 +            contentView.backgroundColor = .pEpGreyBackground
    4.32 +            let languangePicker = UIPickerView()
    4.33 +            languangePicker.dataSource = self
    4.34 +            languangePicker.delegate = self
    4.35 +            contentView.inputView = languangePicker
    4.36 +        }
    4.37 +    }
    4.38 +    @IBOutlet weak var alertTitle: UILabel! {
    4.39 +        didSet {
    4.40 +            let alertTittle = NSLocalizedString("p≡p Sync", comment: "keySync handshake alert title")
    4.41 +            alertTitle.attributedText = alertTittle.paintPEPToPEPColour()
    4.42 +        }
    4.43 +    }
    4.44 +    @IBOutlet weak var message: UILabel! {
    4.45 +        didSet {
    4.46 +            message.text = NSLocalizedString("A second device is detected. \nPlease confirm the Trustwords on both devices to sync all your privacy. Shall we synchronize?", comment: "keySync handshake alert message")
    4.47 +        }
    4.48 +    }
    4.49 +
    4.50 +    @IBOutlet weak var accept: UIButton! {
    4.51 +        didSet {
    4.52 +            accept.setTitleColor(.pEpGreen, for: .normal)
    4.53 +            accept.setTitle(NSLocalizedString("Sync", comment: "accept hand shake sync button"), for: .normal)
    4.54 +            accept.backgroundColor = .pEpGreyBackground
    4.55 +        }
    4.56 +    }
    4.57 +    @IBOutlet weak var decline: UIButton! {
    4.58 +        didSet {
    4.59 +            decline.setTitleColor(.pEpRed, for: .normal)
    4.60 +            decline.setTitle(NSLocalizedString("Decline", comment: "decline button"), for: .normal)
    4.61 +            decline.backgroundColor = .pEpGreyBackground
    4.62 +        }
    4.63 +    }
    4.64 +    @IBOutlet weak var cancel: UIButton! {
    4.65 +        didSet {
    4.66 +            cancel.setTitleColor(.pEpGreyText, for: .normal)
    4.67 +            cancel.setTitle(NSLocalizedString("Not Now", comment: "not now button"), for: .normal)
    4.68 +            cancel.backgroundColor = .pEpGreyBackground
    4.69 +        }
    4.70 +    }
    4.71 +    @IBOutlet weak var buttonsView: UIView! {
    4.72 +        didSet {
    4.73 +            buttonsView.backgroundColor = .pEpGreyButtonLines
    4.74 +        }
    4.75 +    }
    4.76 +
    4.77 +    private let viewModel = KeySyncHandshakeViewModel()
    4.78 +    private var pickerLanguages = [String]()
    4.79 +    private var meFPR: String?
    4.80 +    private var partnerFPR: String?
    4.81 +
    4.82 +    override func viewDidLoad() {
    4.83 +        super.viewDidLoad()
    4.84 +        viewModel.delegate = self
    4.85 +        viewModel.fingerPrints(meFPR: meFPR, partnerFPR: partnerFPR)
    4.86 +    }
    4.87 +
    4.88 +    func finderPrints(meFPR: String, partnerFPR: String) {
    4.89 +        self.meFPR = meFPR
    4.90 +        self.partnerFPR = partnerFPR
    4.91 +    }
    4.92 +
    4.93 +    @IBAction func didPress(_ sender: UIButton) {
    4.94 +        guard let action = pressedAction(tag: sender.tag) else {
    4.95 +            return
    4.96 +        }
    4.97 +        viewModel.handle(action: action)
    4.98 +    }
    4.99 +
   4.100 +    @IBAction func didLongPressWords(_ sender: UILongPressGestureRecognizer) {
   4.101 +        guard sender.state == .began else {
   4.102 +            return
   4.103 +        }
   4.104 +        viewModel.didLongPressWords()
   4.105 +    }
   4.106 +
   4.107 +    func completionHandler(_ block: @escaping (Action) -> Void) {
   4.108 +        viewModel.completionHandler = block
   4.109 +    }
   4.110 +}
   4.111 +
   4.112 +// MARK: - KeySyncHandshakeViewModelDelegate
   4.113 +
   4.114 +extension KeySyncHandshakeViewController: KeySyncHandshakeViewModelDelegate {
   4.115 +    func dissmissView() {
   4.116 +        DispatchQueue.main.async { [weak self] in
   4.117 +            self?.dismiss(animated: true, completion: nil)
   4.118 +        }
   4.119 +    }
   4.120 +
   4.121 +    func showPicker(withLanguages languages: [String]) {
   4.122 +        pickerLanguages = languages
   4.123 +        DispatchQueue.main.async { [weak self] in
   4.124 +            self?.contentView.becomeFirstResponder()
   4.125 +        }
   4.126 +    }
   4.127 +
   4.128 +    func closePicker() {
   4.129 +        DispatchQueue.main.async { [weak self] in
   4.130 +            self?.contentView.resignFirstResponder()
   4.131 +        }
   4.132 +    }
   4.133 +
   4.134 +    func change(handshakeWordsTo: String) {
   4.135 +        DispatchQueue.main.async { [weak self] in
   4.136 +            self?.keySyncWords.text = handshakeWordsTo
   4.137 +        }
   4.138 +    }
   4.139 +}
   4.140 +
   4.141 +// MARK: - UIPickerViewDelegate
   4.142 +extension KeySyncHandshakeViewController: UIPickerViewDelegate {
   4.143 +    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
   4.144 +        return pickerLanguages[row]
   4.145 +    }
   4.146 +
   4.147 +    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
   4.148 +        viewModel.didSelect(languageRow: row)
   4.149 +    }
   4.150 +}
   4.151 +
   4.152 +// MARK: - UIPickerViewDataSource
   4.153 +extension KeySyncHandshakeViewController: UIPickerViewDataSource {
   4.154 +    func numberOfComponents(in pickerView: UIPickerView) -> Int {
   4.155 +        return 1
   4.156 +    }
   4.157 +
   4.158 +    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
   4.159 +        return pickerLanguages.count
   4.160 +    }
   4.161 +}
   4.162 +
   4.163 +// MARK: - Private
   4.164 +extension KeySyncHandshakeViewController {
   4.165 +    private func pressedAction(tag: Int) -> KeySyncHandshakeViewModel.Action? {
   4.166 +        switch tag {
   4.167 +        case 1:
   4.168 +            return .changeLanguage
   4.169 +        case 2:
   4.170 +            return .cancel
   4.171 +        case 3:
   4.172 +            return .decline
   4.173 +        case 4:
   4.174 +            return .accept
   4.175 +        default:
   4.176 +            return nil
   4.177 +        }
   4.178 +    }
   4.179 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/pEpForiOS/UI/KeySyncHandshake/KeySyncHandshakeViewModel.swift	Tue Aug 20 10:02:18 2019 +0200
     5.3 @@ -0,0 +1,120 @@
     5.4 +//
     5.5 +//  KeySyncHandshakeViewModel.swift
     5.6 +//  pEp
     5.7 +//
     5.8 +//  Created by Alejandro Gelos on 05/07/2019.
     5.9 +//  Copyright © 2019 p≡p Security S.A. All rights reserved.
    5.10 +//
    5.11 +
    5.12 +import Foundation
    5.13 +import PEPObjCAdapterFramework
    5.14 +
    5.15 +protocol KeySyncHandshakeViewModelDelegate: class {
    5.16 +    func dissmissView()
    5.17 +    func showPicker(withLanguages languages: [String])
    5.18 +    func closePicker()
    5.19 +    func change(handshakeWordsTo: String)
    5.20 +}
    5.21 +
    5.22 +final class KeySyncHandshakeViewModel {
    5.23 +    enum Action {
    5.24 +        case cancel, decline, accept, changeLanguage
    5.25 +    }
    5.26 +
    5.27 +    var completionHandler: ((KeySyncHandshakeViewController.Action) -> Void)?
    5.28 +
    5.29 +    weak var delegate: KeySyncHandshakeViewModelDelegate?
    5.30 +    var fullTrustWords = false //Internal since testing
    5.31 +    private var languageCode = Locale.current.languageCode
    5.32 +    private var meFPR: String?
    5.33 +    private var partnerFPR: String?
    5.34 +    private let pEpSession: PEPSessionProtocol
    5.35 +    private var _languages = [PEPLanguage]()
    5.36 +    private var languages: [PEPLanguage] {
    5.37 +        guard _languages.isEmpty else {
    5.38 +            return _languages
    5.39 +        }
    5.40 +        do {
    5.41 +            _languages = try pEpSession.languageList()
    5.42 +            return _languages
    5.43 +        } catch {
    5.44 +            Log.shared.errorAndCrash("%@", error.localizedDescription)
    5.45 +            return []
    5.46 +        }
    5.47 +    }
    5.48 +
    5.49 +    init(pEpSession: PEPSessionProtocol = PEPSession()) {
    5.50 +        self.pEpSession = pEpSession
    5.51 +    }
    5.52 +
    5.53 +    func didSelect(languageRow: Int) {
    5.54 +        languageCode = languages[languageRow].code
    5.55 +        delegate?.closePicker()
    5.56 +        delegate?.change(handshakeWordsTo: trustWorkds())
    5.57 +    }
    5.58 +
    5.59 +    func handle(action: Action) {
    5.60 +        switch action {
    5.61 +        case .accept, .cancel, .decline:
    5.62 +            guard let action = viewControllerAction(viewModelAction: action) else {
    5.63 +                return
    5.64 +            }
    5.65 +            completionHandler?(action)
    5.66 +            delegate?.dissmissView()
    5.67 +        case .changeLanguage:
    5.68 +            handleChangeLanguageButton()
    5.69 +        }
    5.70 +    }
    5.71 +
    5.72 +    func fingerPrints(meFPR: String?, partnerFPR: String?) {
    5.73 +        self.meFPR = meFPR
    5.74 +        self.partnerFPR = partnerFPR
    5.75 +        delegate?.change(handshakeWordsTo: trustWorkds())
    5.76 +    }
    5.77 +
    5.78 +    func didLongPressWords() {
    5.79 +        fullTrustWords = !fullTrustWords
    5.80 +        delegate?.change(handshakeWordsTo: trustWorkds())
    5.81 +    }
    5.82 +}
    5.83 +
    5.84 +// MARK: - Private
    5.85 +
    5.86 +extension KeySyncHandshakeViewModel {
    5.87 +    private func trustWorkds() -> String {
    5.88 +        guard let meFPR = meFPR, let partnerFPR = partnerFPR else {
    5.89 +            Log.shared.errorAndCrash("Nil meFingerPrints or Nil partnerFingerPrints")
    5.90 +            return String()
    5.91 +        }
    5.92 +        do {
    5.93 +            return try pEpSession.getTrustwordsFpr1(meFPR, fpr2: partnerFPR, language: languageCode,
    5.94 +                                                      full: fullTrustWords)
    5.95 +        } catch {
    5.96 +            Log.shared.errorAndCrash("%@", error.localizedDescription)
    5.97 +            return ""
    5.98 +        }
    5.99 +    }
   5.100 +
   5.101 +    private func handleChangeLanguageButton() {
   5.102 +        guard !languages.isEmpty else {
   5.103 +            Log.shared.errorAndCrash("Wont show picker, no languages to show")
   5.104 +            return
   5.105 +        }
   5.106 +        let languagesNames = languages.map { $0.name }
   5.107 +        delegate?.showPicker(withLanguages: languagesNames)
   5.108 +    }
   5.109 +
   5.110 +    private func viewControllerAction(viewModelAction: KeySyncHandshakeViewModel.Action)
   5.111 +        -> KeySyncHandshakeViewController.Action? {
   5.112 +            switch viewModelAction {
   5.113 +            case .accept:
   5.114 +                return .accept
   5.115 +            case .cancel:
   5.116 +                return .cancel
   5.117 +            case .decline:
   5.118 +                return .decline
   5.119 +            case .changeLanguage:
   5.120 +                return nil
   5.121 +            }
   5.122 +    }
   5.123 +}
     6.1 --- a/pEpForiOS/UI/Util/Extensions/UIViewController+Extension.swift	Fri Aug 16 14:15:14 2019 +0200
     6.2 +++ b/pEpForiOS/UI/Util/Extensions/UIViewController+Extension.swift	Tue Aug 20 10:02:18 2019 +0200
     6.3 @@ -40,4 +40,22 @@
     6.4              return nil
     6.5          }
     6.6      }
     6.7 +
     6.8 +    func presentKeySyncHandShakeAlert(meFPR: String, partnerFPR: String,
     6.9 +                        completion: @escaping (KeySyncHandshakeViewController.Action) -> Void ) {
    6.10 +
    6.11 +        let storyboard = UIStoryboard(name: Constants.suggestionsStoryboard, bundle: .main)
    6.12 +        guard let handShakeViewController = storyboard.instantiateViewController(
    6.13 +            withIdentifier: KeySyncHandshakeViewController.storyboardId) as? KeySyncHandshakeViewController else {
    6.14 +                Log.shared.errorAndCrash("Fail to instantiateViewController KeySyncHandshakeViewController")
    6.15 +                return
    6.16 +        }
    6.17 +        handShakeViewController.completionHandler { action in
    6.18 +            completion(action)
    6.19 +        }
    6.20 +        handShakeViewController.finderPrints(meFPR: meFPR, partnerFPR: partnerFPR)
    6.21 +
    6.22 +        handShakeViewController.modalPresentationStyle = .overFullScreen
    6.23 +        present(handShakeViewController, animated: true, completion: nil)
    6.24 +    }
    6.25  }
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/pEpForiOS/UI/Util/KeyInputView.swift	Tue Aug 20 10:02:18 2019 +0200
     7.3 @@ -0,0 +1,30 @@
     7.4 +//
     7.5 +//  KeyInputView.swift
     7.6 +//  pEp
     7.7 +//
     7.8 +//  Created by Alejandro Gelos on 15/07/2019.
     7.9 +//  Copyright © 2019 p≡p Security S.A. All rights reserved.
    7.10 +//
    7.11 +
    7.12 +import UIKit
    7.13 +
    7.14 +class KeyInputView: UIView {
    7.15 +    var _inputView: UIView?
    7.16 +
    7.17 +    override var canBecomeFirstResponder: Bool { return true }
    7.18 +    override var canResignFirstResponder: Bool { return true }
    7.19 +
    7.20 +    override var inputView: UIView? {
    7.21 +        set { _inputView = newValue }
    7.22 +        get { return _inputView }
    7.23 +    }
    7.24 +}
    7.25 +
    7.26 +// MARK: - UIKeyInput
    7.27 +
    7.28 +//Modify if need more functionality
    7.29 +extension KeyInputView: UIKeyInput {
    7.30 +    var hasText: Bool { return false }
    7.31 +    func insertText(_ text: String) {}
    7.32 +    func deleteBackward() {}
    7.33 +}
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/pEpForiOSTests/UI/KeySyncHandshake/KeySyncHandshakeViewModelTest.swift	Tue Aug 20 10:02:18 2019 +0200
     8.3 @@ -0,0 +1,220 @@
     8.4 +//
     8.5 +//  KeySyncHandshakeViewModelTest.swift
     8.6 +//  pEpForiOSTests
     8.7 +//
     8.8 +//  Created by Alejandro Gelos on 05/07/2019.
     8.9 +//  Copyright © 2019 p≡p Security S.A. All rights reserved.
    8.10 +//
    8.11 +
    8.12 +import XCTest
    8.13 +@testable import pEpForiOS
    8.14 +
    8.15 +final class KeySyncHandshakeViewModelTest: XCTestCase {
    8.16 +
    8.17 +    var keySyncHandshakeVM: KeySyncHandshakeViewModel?
    8.18 +    var actual: State?
    8.19 +    var expected: State?
    8.20 +
    8.21 +    override func setUp() {
    8.22 +        super.setUp()
    8.23 +
    8.24 +        keySyncHandshakeVM = KeySyncHandshakeViewModel(pEpSession: PEPSessionMoc())
    8.25 +        keySyncHandshakeVM?.fingerPrints(meFPR: "", partnerFPR: "")
    8.26 +        keySyncHandshakeVM?.delegate = self
    8.27 +
    8.28 +        setDefaultActualState()
    8.29 +        keySyncHandshakeVM?.completionHandler = { [weak self] action in
    8.30 +            self?.actual?.pressedAction = action
    8.31 +        }
    8.32 +        expected = nil
    8.33 +    }
    8.34 +
    8.35 +    override func tearDown() {
    8.36 +        keySyncHandshakeVM?.delegate = nil
    8.37 +        keySyncHandshakeVM = nil
    8.38 +        actual = nil
    8.39 +        expected = nil
    8.40 +
    8.41 +        super.tearDown()
    8.42 +    }
    8.43 +
    8.44 +    func testDidSelectLanguageToOtherOrSame() {
    8.45 +        // GIVEN
    8.46 +        guard let keySyncHandshakeVM = keySyncHandshakeVM else {
    8.47 +            XCTFail()
    8.48 +            return
    8.49 +        }
    8.50 +        expected = State(didCallClosePicker: true, didCallToUpdateTrustedWords: true)
    8.51 +
    8.52 +        // WHEN
    8.53 +        keySyncHandshakeVM.didSelect(languageRow: 0)
    8.54 +
    8.55 +        // THEN
    8.56 +        assertExpectations()
    8.57 +    }
    8.58 +
    8.59 +    func testDidPressActionAccept() {
    8.60 +        // GIVEN
    8.61 +        guard let keySyncHandshakeVM = keySyncHandshakeVM else {
    8.62 +            XCTFail()
    8.63 +            return
    8.64 +        }
    8.65 +        expected = State(didCallDissmissView: true, pressedAction: .accept)
    8.66 +
    8.67 +        // WHEN
    8.68 +        keySyncHandshakeVM.handle(action: .accept)
    8.69 +
    8.70 +        // THEN
    8.71 +        assertExpectations()
    8.72 +    }
    8.73 +
    8.74 +    func testDidPressActionChangeLanguage() {
    8.75 +        // GIVEN
    8.76 +        guard let keySyncHandshakeVM = keySyncHandshakeVM else {
    8.77 +            XCTFail()
    8.78 +            return
    8.79 +        }
    8.80 +        expected = State(didCallShowPicker: true, languagesToShow: ["", ""])
    8.81 +
    8.82 +        // WHEN
    8.83 +        keySyncHandshakeVM.handle(action: .changeLanguage)
    8.84 +
    8.85 +        // THEN
    8.86 +        assertExpectations()
    8.87 +    }
    8.88 +
    8.89 +    func testDidPressActionDecline() {
    8.90 +        // GIVEN
    8.91 +        guard let keySyncHandshakeVM = keySyncHandshakeVM else {
    8.92 +            XCTFail()
    8.93 +            return
    8.94 +        }
    8.95 +        expected = State(didCallDissmissView: true, pressedAction: .decline)
    8.96 +
    8.97 +        // WHEN
    8.98 +        keySyncHandshakeVM.handle(action: .decline)
    8.99 +
   8.100 +        // THEN
   8.101 +        assertExpectations()
   8.102 +    }
   8.103 +
   8.104 +    func testDidPressActionCancel() {
   8.105 +        // GIVEN
   8.106 +        guard let keySyncHandshakeVM = keySyncHandshakeVM else {
   8.107 +            XCTFail()
   8.108 +            return
   8.109 +        }
   8.110 +        expected = State(didCallDissmissView: true, pressedAction: .cancel)
   8.111 +
   8.112 +        // WHEN
   8.113 +        keySyncHandshakeVM.handle(action: .cancel)
   8.114 +
   8.115 +        // THEN
   8.116 +        assertExpectations()
   8.117 +    }
   8.118 +
   8.119 +    func testDidLongPressWords() {
   8.120 +        // GIVEN
   8.121 +        guard let keySyncHandshakeVM = keySyncHandshakeVM else {
   8.122 +            XCTFail()
   8.123 +            return
   8.124 +        }
   8.125 +        expected = State(didCallToUpdateTrustedWords: true, fullWordsVersion: true)
   8.126 +
   8.127 +        // WHEN
   8.128 +        keySyncHandshakeVM.didLongPressWords()
   8.129 +
   8.130 +        // THEN
   8.131 +        assertExpectations()
   8.132 +    }
   8.133 +}
   8.134 +
   8.135 +// MARK: - KeySyncHandshakeViewModelDelegate
   8.136 +
   8.137 +extension KeySyncHandshakeViewModelTest: KeySyncHandshakeViewModelDelegate {
   8.138 +    func dissmissView() {
   8.139 +        actual?.didCallDissmissView = true
   8.140 +    }
   8.141 +
   8.142 +    func closePicker() {
   8.143 +        actual?.didCallClosePicker = true
   8.144 +    }
   8.145 +
   8.146 +    func showPicker(withLanguages languages: [String]) {
   8.147 +        actual?.didCallShowPicker = true
   8.148 +        actual?.languagesToShow = languages
   8.149 +    }
   8.150 +
   8.151 +    func change(handshakeWordsTo: String) {
   8.152 +        actual?.didCallToUpdateTrustedWords = true
   8.153 +        actual?.fullWordsVersion = keySyncHandshakeVM?.fullTrustWords
   8.154 +    }
   8.155 +}
   8.156 +
   8.157 +// MARK: - Private
   8.158 +
   8.159 +extension KeySyncHandshakeViewModelTest {
   8.160 +    private func setDefaultActualState() {
   8.161 +        actual = State()
   8.162 +    }
   8.163 +
   8.164 +    private func assertExpectations() {
   8.165 +        guard let expected = expected,
   8.166 +            let actual = actual else {
   8.167 +                XCTFail()
   8.168 +                return
   8.169 +        }
   8.170 +
   8.171 +        //bools
   8.172 +        XCTAssertEqual(expected.didCallShowPicker, actual.didCallShowPicker)
   8.173 +        XCTAssertEqual(expected.didCallClosePicker, actual.didCallClosePicker)
   8.174 +        XCTAssertEqual(expected.didCallDissmissView, actual.didCallDissmissView)
   8.175 +        XCTAssertEqual(expected.didCallToUpdateTrustedWords, actual.didCallToUpdateTrustedWords)
   8.176 +
   8.177 +        //values
   8.178 +        XCTAssertEqual(expected.fullWordsVersion, actual.fullWordsVersion)
   8.179 +        XCTAssertEqual(expected.languagesToShow, actual.languagesToShow)
   8.180 +        XCTAssertEqual(expected.handShakeWords, actual.handShakeWords)
   8.181 +        XCTAssertEqual(expected.pressedAction, actual.pressedAction)
   8.182 +
   8.183 +        //In case some if missing or added but not checked
   8.184 +        XCTAssertEqual(expected, actual)
   8.185 +    }
   8.186 +}
   8.187 +
   8.188 +
   8.189 +// MARK: - Helper Structs
   8.190 +extension KeySyncHandshakeViewModelTest {
   8.191 +    struct State: Equatable {
   8.192 +        var didCallShowPicker: Bool
   8.193 +        var didCallClosePicker: Bool
   8.194 +        var didCallDissmissView: Bool
   8.195 +        var didCallToUpdateTrustedWords: Bool
   8.196 +
   8.197 +        var fullWordsVersion: Bool?
   8.198 +        var languagesToShow: [String]?
   8.199 +        var handShakeWords: String?
   8.200 +        var pressedAction: KeySyncHandshakeViewController.Action?
   8.201 +
   8.202 +        // Default value are default initial state
   8.203 +        init(didCallShowPicker: Bool = false,
   8.204 +             didCallClosePicker: Bool = false,
   8.205 +             didCallDissmissView: Bool = false,
   8.206 +             didCallToUpdateTrustedWords: Bool = false,
   8.207 +             fullWordsVersion: Bool = false,
   8.208 +             languagesToShow: [String] = [],
   8.209 +             handShakeWords: String = "",
   8.210 +             pressedAction: KeySyncHandshakeViewController.Action? = nil) {
   8.211 +
   8.212 +            self.didCallShowPicker = didCallShowPicker
   8.213 +            self.didCallClosePicker = didCallClosePicker
   8.214 +            self.didCallDissmissView = didCallDissmissView
   8.215 +            self.didCallToUpdateTrustedWords = didCallToUpdateTrustedWords
   8.216 +
   8.217 +            self.fullWordsVersion = fullWordsVersion
   8.218 +            self.languagesToShow = languagesToShow
   8.219 +            self.handShakeWords = handShakeWords
   8.220 +            self.pressedAction = pressedAction
   8.221 +        }
   8.222 +    }
   8.223 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/pEpForiOSTests/UI/KeySyncHandshake/PEPSessionMoc.swift	Tue Aug 20 10:02:18 2019 +0200
     9.3 @@ -0,0 +1,146 @@
     9.4 +//
     9.5 +//  PEPSessionMoc.swift
     9.6 +//  pEpForiOSTests
     9.7 +//
     9.8 +//  Created by Alejandro Gelos on 09/07/2019.
     9.9 +//  Copyright © 2019 p≡p Security S.A. All rights reserved.
    9.10 +//
    9.11 +
    9.12 +import Foundation
    9.13 +import PEPObjCAdapterFramework
    9.14 +
    9.15 +class PEPSessionMoc: NSObject, PEPSessionProtocol  {
    9.16 +    func decryptMessageDict(_ messageDict: NSMutableDictionary, flags: UnsafeMutablePointer<PEPDecryptFlags>?, rating: UnsafeMutablePointer<PEPRating>?, extraKeys: AutoreleasingUnsafeMutablePointer<NSArray?>?, status: UnsafeMutablePointer<PEPStatus>?) throws -> [String : Any] {
    9.17 +        return [:]
    9.18 +    }
    9.19 +
    9.20 +    func decryptMessage(_ message: PEPMessage, flags: UnsafeMutablePointer<PEPDecryptFlags>?, rating: UnsafeMutablePointer<PEPRating>?, extraKeys: AutoreleasingUnsafeMutablePointer<NSArray?>?, status: UnsafeMutablePointer<PEPStatus>?) throws -> PEPMessage {
    9.21 +        return PEPMessage()
    9.22 +    }
    9.23 +
    9.24 +    func reEvaluateMessageDict(_ messageDict: [String : Any], xKeyList: [String]?, rating: UnsafeMutablePointer<PEPRating>, status: UnsafeMutablePointer<PEPStatus>?) throws {
    9.25 +    }
    9.26 +
    9.27 +    func reEvaluateMessage(_ message: PEPMessage, xKeyList: [String]?, rating: UnsafeMutablePointer<PEPRating>, status: UnsafeMutablePointer<PEPStatus>?) throws {
    9.28 +    }
    9.29 +
    9.30 +    func encryptMessageDict(_ messageDict: [String : Any], extraKeys: [String]?, encFormat: PEPEncFormat, status: UnsafeMutablePointer<PEPStatus>?) throws -> [String : Any] {
    9.31 +        return [:]
    9.32 +    }
    9.33 +
    9.34 +    func encryptMessage(_ message: PEPMessage, extraKeys: [String]?, encFormat: PEPEncFormat, status: UnsafeMutablePointer<PEPStatus>?) throws -> PEPMessage {
    9.35 +        return PEPMessage()
    9.36 +    }
    9.37 +
    9.38 +    func encryptMessage(_ message: PEPMessage, extraKeys: [String]?, status: UnsafeMutablePointer<PEPStatus>?) throws -> PEPMessage {
    9.39 +        return PEPMessage()
    9.40 +    }
    9.41 +
    9.42 +    func encryptMessageDict(_ messageDict: [String : Any], forSelf ownIdentity: PEPIdentity, extraKeys: [String]?, status: UnsafeMutablePointer<PEPStatus>?) throws -> [String : Any] {
    9.43 +        return [:]
    9.44 +    }
    9.45 +
    9.46 +    func encryptMessage(_ message: PEPMessage, forSelf ownIdentity: PEPIdentity, extraKeys: [String]?, status: UnsafeMutablePointer<PEPStatus>?) throws -> PEPMessage {
    9.47 +        return PEPMessage()
    9.48 +    }
    9.49 +
    9.50 +    func encryptMessageDict(_ messageDict: [String : Any], toFpr: String, encFormat: PEPEncFormat, flags: PEPDecryptFlags, status: UnsafeMutablePointer<PEPStatus>?) throws -> [String : Any] {
    9.51 +        return [:]
    9.52 +    }
    9.53 +
    9.54 +    func encryptMessage(_ message: PEPMessage, toFpr: String, encFormat: PEPEncFormat, flags: PEPDecryptFlags, status: UnsafeMutablePointer<PEPStatus>?) throws -> PEPMessage {
    9.55 +        return PEPMessage()
    9.56 +    }
    9.57 +
    9.58 +    func outgoingRating(for theMessage: PEPMessage) throws -> NSNumber {
    9.59 +        return 0
    9.60 +    }
    9.61 +
    9.62 +    func outgoingRatingPreview(for theMessage: PEPMessage) throws -> NSNumber {
    9.63 +        return 0
    9.64 +    }
    9.65 +
    9.66 +    func rating(for identity: PEPIdentity) throws -> NSNumber {
    9.67 +        return 0
    9.68 +    }
    9.69 +
    9.70 +    func trustwords(forFingerprint fingerprint: String, languageID: String, shortened: Bool) throws -> [Any] {
    9.71 +        return []
    9.72 +    }
    9.73 +
    9.74 +    func mySelf(_ identity: PEPIdentity) throws {
    9.75 +    }
    9.76 +
    9.77 +    func update(_ identity: PEPIdentity) throws {
    9.78 +    }
    9.79 +
    9.80 +    func trustPersonalKey(_ identity: PEPIdentity) throws {
    9.81 +    }
    9.82 +
    9.83 +    func keyMistrusted(_ identity: PEPIdentity) throws {
    9.84 +    }
    9.85 +
    9.86 +    func keyResetTrust(_ identity: PEPIdentity) throws {
    9.87 +    }
    9.88 +
    9.89 +    func importKey(_ keydata: String) throws -> [PEPIdentity] {
    9.90 +        return []
    9.91 +    }
    9.92 +
    9.93 +    func logTitle(_ title: String, entity: String, description: String?, comment: String?) throws {
    9.94 +    }
    9.95 +
    9.96 +    func getLog() throws -> String {
    9.97 +        return String()
    9.98 +    }
    9.99 +
   9.100 +    func getTrustwordsIdentity1(_ identity1: PEPIdentity, identity2: PEPIdentity, language: String?, full: Bool) throws -> String {
   9.101 +        return String()
   9.102 +    }
   9.103 +
   9.104 +    func getTrustwordsFpr1(_ fpr1: String, fpr2: String, language: String?, full: Bool) throws -> String {
   9.105 +        return String()
   9.106 +    }
   9.107 +
   9.108 +    func languageList() throws -> [PEPLanguage] {
   9.109 +        return [PEPLanguage(), PEPLanguage()]
   9.110 +    }
   9.111 +
   9.112 +    func rating(from string: String) -> PEPRating {
   9.113 +        return .fullyAnonymous
   9.114 +    }
   9.115 +
   9.116 +    func string(from rating: PEPRating) -> String {
   9.117 +        return String()
   9.118 +    }
   9.119 +
   9.120 +    func isPEPUser(_ identity: PEPIdentity) throws -> NSNumber {
   9.121 +        return 0
   9.122 +    }
   9.123 +
   9.124 +    func setOwnKey(_ identity: PEPIdentity, fingerprint: String) throws {
   9.125 +    }
   9.126 +
   9.127 +    func configurePassiveModeEnabled(_ enabled: Bool) {
   9.128 +    }
   9.129 +
   9.130 +    func setFlags(_ flags: PEPIdentityFlags, for identity: PEPIdentity) throws {
   9.131 +    }
   9.132 +
   9.133 +    func deliver(_ result: PEPSyncHandshakeResult, identitiesSharing: [PEPIdentity]?) throws {
   9.134 +    }
   9.135 +
   9.136 +    func trustOwnKeyIdentity(_ identity: PEPIdentity) throws {
   9.137 +    }
   9.138 +
   9.139 +    func color(from rating: PEPRating) -> PEPColor {
   9.140 +        return .green
   9.141 +    }
   9.142 +
   9.143 +    func keyReset(_ identity: PEPIdentity, fingerprint: String?) throws {
   9.144 +    }
   9.145 +
   9.146 +    func leaveDeviceGroupError() throws {
   9.147 +    }
   9.148 +
   9.149 +}
    10.1 --- a/subModules/pEpIOSToolbox/pEpIOSToolbox.xcodeproj/project.pbxproj	Fri Aug 16 14:15:14 2019 +0200
    10.2 +++ b/subModules/pEpIOSToolbox/pEpIOSToolbox.xcodeproj/project.pbxproj	Tue Aug 20 10:02:18 2019 +0200
    10.3 @@ -10,6 +10,7 @@
    10.4  		154944CF229A97AA00CC6431 /* SelfReferencingOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 154944CE229A97AA00CC6431 /* SelfReferencingOperation.swift */; };
    10.5  		370DB3CF22804A3600BC929A /* NSSecureCoding+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370DB3CE22804A3600BC929A /* NSSecureCoding+Extension.swift */; };
    10.6  		378B76552240F93A00D6662C /* TestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 378B76542240F93A00D6662C /* TestUtils.swift */; };
    10.7 +		37903EE422FD667700E0AB39 /* String+pEp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37903EE322FD667700E0AB39 /* String+pEp.swift */; };
    10.8  		37904562223FA486006DAB3B /* NetworkReachabilityProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3790455E223FA486006DAB3B /* NetworkReachabilityProtocol.swift */; };
    10.9  		37904563223FA486006DAB3B /* Reachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3790455F223FA486006DAB3B /* Reachability.swift */; };
   10.10  		37904564223FA486006DAB3B /* NetworkReachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37904560223FA486006DAB3B /* NetworkReachability.swift */; };
   10.11 @@ -60,6 +61,7 @@
   10.12  		154944CE229A97AA00CC6431 /* SelfReferencingOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SelfReferencingOperation.swift; path = ../../../../Submodules/pEpIOSToolbox/pEpIOSToolbox/Other/SelfReferencingOperation.swift; sourceTree = "<group>"; };
   10.13  		370DB3CE22804A3600BC929A /* NSSecureCoding+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSSecureCoding+Extension.swift"; sourceTree = "<group>"; };
   10.14  		378B76542240F93A00D6662C /* TestUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TestUtils.swift; path = ../../../../Submodules/pEpIOSToolbox/pEpIOSToolboxTests/TestUtils/TestUtils.swift; sourceTree = "<group>"; };
   10.15 +		37903EE322FD667700E0AB39 /* String+pEp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "String+pEp.swift"; path = "../../../../Submodules/pEpIOSToolbox/pEpIOSToolbox/Foundation/String+pEp.swift"; sourceTree = "<group>"; };
   10.16  		3790455E223FA486006DAB3B /* NetworkReachabilityProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkReachabilityProtocol.swift; sourceTree = "<group>"; };
   10.17  		3790455F223FA486006DAB3B /* Reachability.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Reachability.swift; sourceTree = "<group>"; };
   10.18  		37904560223FA486006DAB3B /* NetworkReachability.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkReachability.swift; sourceTree = "<group>"; };
   10.19 @@ -194,6 +196,7 @@
   10.20  				B7A46C5D220DBAF00027CCB5 /* OperationQueue+Extension.swift */,
   10.21  				B7465DBD22119D39008A1708 /* Thread+Extension.swift */,
   10.22  				B7465DC522119EB1008A1708 /* Array+SortingAndSearching.swift */,
   10.23 +				37903EE322FD667700E0AB39 /* String+pEp.swift */,
   10.24  			);
   10.25  			path = Foundation;
   10.26  			sourceTree = "<group>";
   10.27 @@ -418,6 +421,7 @@
   10.28  				B7911EC221F8694100D7F66F /* UIColor+Extension.swift in Sources */,
   10.29  				B753907E2212D6B500B1FCF9 /* CGSize+Extension.swift in Sources */,
   10.30  				B7DB7F522213120B003968DA /* SortedSet.swift in Sources */,
   10.31 +				37903EE422FD667700E0AB39 /* String+pEp.swift in Sources */,
   10.32  				B7911EC621F88AF800D7F66F /* UIImage+Extension.swift in Sources */,
   10.33  				B70A3A77220091D400EDCE61 /* Logger.swift in Sources */,
   10.34  				B7A46C56220DA5EB0027CCB5 /* Substring+Email.swift in Sources */,
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/subModules/pEpIOSToolbox/pEpIOSToolbox/Foundation/String+pEp.swift	Tue Aug 20 10:02:18 2019 +0200
    11.3 @@ -0,0 +1,20 @@
    11.4 +//
    11.5 +//  String+pEp.swift
    11.6 +//  pEpIOSToolbox
    11.7 +//
    11.8 +//  Created by Alejandro Gelos on 09/08/2019.
    11.9 +//  Copyright © 2019 pEp Security SA. All rights reserved.
   11.10 +//
   11.11 +
   11.12 +import UIKit
   11.13 +
   11.14 +extension String {
   11.15 +    public func paintPEPToPEPColour() -> NSAttributedString {
   11.16 +        let range = (self as NSString).range(of: "p≡p")
   11.17 +        let paintedText = NSMutableAttributedString(string: self)
   11.18 +
   11.19 +        paintedText.addAttribute(
   11.20 +            NSAttributedString.Key.foregroundColor, value: UIColor.pEpGreen, range: range)
   11.21 +        return paintedText
   11.22 +    }
   11.23 +}
    12.1 --- a/subModules/pEpIOSToolbox/pEpIOSToolbox/UIKit/UIColor+Extension.swift	Fri Aug 16 14:15:14 2019 +0200
    12.2 +++ b/subModules/pEpIOSToolbox/pEpIOSToolbox/UIKit/UIColor+Extension.swift	Tue Aug 20 10:02:18 2019 +0200
    12.3 @@ -13,6 +13,10 @@
    12.4      public static let pEpDarkGreenHex = "#1AAA50"
    12.5      public static let pEpRedHex = "#FF3B30"
    12.6      public static let pEpGreyHex = "#8e8e93"
    12.7 +    public static let pEpGreyLinesHex = "#9F9F9F"
    12.8 +    public static let pEpGreyButtonLinesHex = "#CDCED2"
    12.9 +    public static let pEpGreyTextHex = "#8A8A8F"
   12.10 +    public static let pEpGreyBackgroundHex = "#EDEEED"
   12.11      public static let pEpYellowHex = "#FFCC00"
   12.12      public static let pEpLightBackgroundHex = "#F2F2F2"
   12.13      public static let pEpNavigationBarColor = "#f7f7f7"
   12.14 @@ -23,6 +27,10 @@
   12.15      public static var pEpGray = UIColor(hexString: pEpGreyHex)
   12.16      public static var pEpYellow = UIColor(hexString: pEpYellowHex)
   12.17      public static var pEpNavigation = UIColor(hexString: pEpNavigationBarColor)
   12.18 +    public static var pEpGreyLines = UIColor(hexString: pEpGreyLinesHex)
   12.19 +    public static var pEpGreyButtonLines = UIColor(hexString: pEpGreyButtonLinesHex)
   12.20 +    public static var pEpGreyText = UIColor(hexString: pEpGreyTextHex)
   12.21 +    public static var pEpGreyBackground = UIColor(hexString: pEpGreyBackgroundHex)
   12.22  
   12.23      public static let AppleRed =
   12.24                  UIColor(red: 255/255.0, green: 59/255, blue: 48/255.0, alpha: 1.0)