Merge branch 'release/v0.11.3'

This commit is contained in:
SBiOSoftWhare 2020-05-07 18:12:12 +02:00
commit fd8ebb29d4
55 changed files with 1510 additions and 192 deletions

View file

@ -1,3 +1,16 @@
Changes in 0.11.3 (2020-05-07)
===============================================
Improvements:
* Upgrade MatrixKit version ([v0.12.3](https://github.com/matrix-org/matrix-ios-kit/releases/tag/v0.12.3)).
* Cross-signing: Display "Verify your other sessions" modal at every startup if needed (#3180).
* Cross-signing: The "Complete Security" button now triggers a verification request to all user devices.
* Secrets: On startup, request again private keys we are missing locally.
Bug fix:
* KeyVerificationSelfVerifyStartViewController has no navigation (#3195).
* Self-verification: QR code scanning screen refers to other-person scanning (#3189).
Changes in 0.11.2 (2020-05-01)
===============================================

View file

@ -7,7 +7,7 @@ use_frameworks!
# Different flavours of pods to MatrixKit
# The current MatrixKit pod version
$matrixKitVersion = '0.12.2'
$matrixKitVersion = '0.12.3'
# The develop branch version
#$matrixKitVersion = 'develop'

View file

@ -50,38 +50,38 @@ PODS:
- MatomoTracker (7.2.0):
- MatomoTracker/Core (= 7.2.0)
- MatomoTracker/Core (7.2.0)
- MatrixKit (0.12.2):
- MatrixKit (0.12.3):
- cmark (~> 0.24.1)
- DTCoreText (~> 1.6.21)
- HPGrowingTextView (~> 1.1)
- libPhoneNumber-iOS (~> 0.9.13)
- MatrixKit/Core (= 0.12.2)
- MatrixSDK (= 0.16.2)
- MatrixKit/AppExtension (0.12.2):
- MatrixKit/Core (= 0.12.3)
- MatrixSDK (= 0.16.3)
- MatrixKit/AppExtension (0.12.3):
- cmark (~> 0.24.1)
- DTCoreText (~> 1.6.21)
- DTCoreText/Extension
- HPGrowingTextView (~> 1.1)
- libPhoneNumber-iOS (~> 0.9.13)
- MatrixSDK (= 0.16.2)
- MatrixKit/Core (0.12.2):
- MatrixSDK (= 0.16.3)
- MatrixKit/Core (0.12.3):
- cmark (~> 0.24.1)
- DTCoreText (~> 1.6.21)
- HPGrowingTextView (~> 1.1)
- libPhoneNumber-iOS (~> 0.9.13)
- MatrixSDK (= 0.16.2)
- MatrixSDK (0.16.2):
- MatrixSDK/Core (= 0.16.2)
- MatrixSDK/Core (0.16.2):
- MatrixSDK (= 0.16.3)
- MatrixSDK (0.16.3):
- MatrixSDK/Core (= 0.16.3)
- MatrixSDK/Core (0.16.3):
- AFNetworking (~> 3.2.0)
- GZIP (~> 1.2.2)
- libbase58 (~> 0.1.4)
- OLMKit (~> 3.1.0)
- Realm (~> 3.17.3)
- MatrixSDK/JingleCallStack (0.16.2):
- MatrixSDK/JingleCallStack (0.16.3):
- JitsiMeetSDK (~> 2.3.1)
- MatrixSDK/Core
- MatrixSDK/SwiftSupport (0.16.2):
- MatrixSDK/SwiftSupport (0.16.3):
- MatrixSDK/Core
- OLMKit (3.1.0):
- OLMKit/olmc (= 3.1.0)
@ -109,8 +109,8 @@ DEPENDENCIES:
- GBDeviceInfo (~> 6.3.0)
- KTCenterFlowLayout (~> 1.3.1)
- MatomoTracker (~> 7.2.0)
- MatrixKit (= 0.12.2)
- MatrixKit/AppExtension (= 0.12.2)
- MatrixKit (= 0.12.3)
- MatrixKit/AppExtension (= 0.12.3)
- MatrixSDK/JingleCallStack
- MatrixSDK/SwiftSupport
- OLMKit
@ -159,8 +159,8 @@ SPEC CHECKSUMS:
libbase58: 7c040313537b8c44b6e2d15586af8e21f7354efd
libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75
MatomoTracker: 6f89e2561083685a360e223fb663e9ccd57c1d1a
MatrixKit: 93d2c002db0aa0e0b09bd501313fb16122ff4732
MatrixSDK: 613dba898bbeb7823034b7b30418d89be263c20d
MatrixKit: fbf24e0e62878e76ac5e28ed10649b37cbdf5cfc
MatrixSDK: e0adc76d921d7a50eb6031ed5c7cf3342c8f3166
OLMKit: 4ee0159d63feeb86d836fdcfefe418e163511639
Realm: 5a1d9d47bfc101dd597668b1a8af4288a2557f6d
Reusable: 82be188f29d96dc5eff0db7b2393bcc08d2cdd5b
@ -169,6 +169,6 @@ SPEC CHECKSUMS:
zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
PODFILE CHECKSUM: d3b15ac72eb62dce4f4a61be16d91599412be420
PODFILE CHECKSUM: 1775b118460fd52106eea1e61084b3afb948de7f
COCOAPODS: 1.9.1

View file

@ -210,6 +210,14 @@
B140B4A821F8AB4600E3F5FE /* KeyBackupRecoverCoordinatorBridgePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B140B4A721F8AB4600E3F5FE /* KeyBackupRecoverCoordinatorBridgePresenter.swift */; };
B142317A22CCFA2000FFA96A /* EditHistoryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B142317822CCFA2000FFA96A /* EditHistoryCell.swift */; };
B142317B22CCFA2000FFA96A /* EditHistoryCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B142317922CCFA2000FFA96A /* EditHistoryCell.xib */; };
B14B17602462C69000C2751E /* KeyVerificationManuallyVerifyViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14B17582462C68F00C2751E /* KeyVerificationManuallyVerifyViewAction.swift */; };
B14B17612462C69000C2751E /* KeyVerificationManuallyVerifyCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14B17592462C68F00C2751E /* KeyVerificationManuallyVerifyCoordinator.swift */; };
B14B17622462C69000C2751E /* KeyVerificationManuallyVerifyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14B175A2462C68F00C2751E /* KeyVerificationManuallyVerifyViewController.swift */; };
B14B17632462C69000C2751E /* KeyVerificationManuallyVerifyViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B14B175B2462C68F00C2751E /* KeyVerificationManuallyVerifyViewController.storyboard */; };
B14B17642462C69000C2751E /* KeyVerificationManuallyVerifyViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14B175C2462C68F00C2751E /* KeyVerificationManuallyVerifyViewModelType.swift */; };
B14B17652462C69000C2751E /* KeyVerificationManuallyVerifyViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14B175D2462C68F00C2751E /* KeyVerificationManuallyVerifyViewModel.swift */; };
B14B17662462C69000C2751E /* KeyVerificationManuallyVerifyCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14B175E2462C68F00C2751E /* KeyVerificationManuallyVerifyCoordinatorType.swift */; };
B14B17672462C69000C2751E /* KeyVerificationManuallyVerifyViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14B175F2462C68F00C2751E /* KeyVerificationManuallyVerifyViewState.swift */; };
B14F142E22144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B14F142622144F6400FA0595 /* KeyBackupRecoverFromRecoveryKeyViewController.storyboard */; };
B14F142F22144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14F142722144F6400FA0595 /* KeyBackupRecoverFromRecoveryKeyViewModelType.swift */; };
B14F143022144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14F142822144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyCoordinatorType.swift */; };
@ -1004,6 +1012,14 @@
B140B4A721F8AB4600E3F5FE /* KeyBackupRecoverCoordinatorBridgePresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyBackupRecoverCoordinatorBridgePresenter.swift; sourceTree = "<group>"; };
B142317822CCFA2000FFA96A /* EditHistoryCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditHistoryCell.swift; sourceTree = "<group>"; };
B142317922CCFA2000FFA96A /* EditHistoryCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = EditHistoryCell.xib; sourceTree = "<group>"; };
B14B17582462C68F00C2751E /* KeyVerificationManuallyVerifyViewAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyVerificationManuallyVerifyViewAction.swift; sourceTree = "<group>"; };
B14B17592462C68F00C2751E /* KeyVerificationManuallyVerifyCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyVerificationManuallyVerifyCoordinator.swift; sourceTree = "<group>"; };
B14B175A2462C68F00C2751E /* KeyVerificationManuallyVerifyViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyVerificationManuallyVerifyViewController.swift; sourceTree = "<group>"; };
B14B175B2462C68F00C2751E /* KeyVerificationManuallyVerifyViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = KeyVerificationManuallyVerifyViewController.storyboard; sourceTree = "<group>"; };
B14B175C2462C68F00C2751E /* KeyVerificationManuallyVerifyViewModelType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyVerificationManuallyVerifyViewModelType.swift; sourceTree = "<group>"; };
B14B175D2462C68F00C2751E /* KeyVerificationManuallyVerifyViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyVerificationManuallyVerifyViewModel.swift; sourceTree = "<group>"; };
B14B175E2462C68F00C2751E /* KeyVerificationManuallyVerifyCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyVerificationManuallyVerifyCoordinatorType.swift; sourceTree = "<group>"; };
B14B175F2462C68F00C2751E /* KeyVerificationManuallyVerifyViewState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyVerificationManuallyVerifyViewState.swift; sourceTree = "<group>"; };
B14F142622144F6400FA0595 /* KeyBackupRecoverFromRecoveryKeyViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = KeyBackupRecoverFromRecoveryKeyViewController.storyboard; sourceTree = "<group>"; };
B14F142722144F6400FA0595 /* KeyBackupRecoverFromRecoveryKeyViewModelType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyBackupRecoverFromRecoveryKeyViewModelType.swift; sourceTree = "<group>"; };
B14F142822144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyBackupRecoverFromRecoveryKeyCoordinatorType.swift; sourceTree = "<group>"; };
@ -2312,6 +2328,21 @@
path = Start;
sourceTree = "<group>";
};
B14B17572462C68F00C2751E /* ManuallyVerify */ = {
isa = PBXGroup;
children = (
B14B175E2462C68F00C2751E /* KeyVerificationManuallyVerifyCoordinatorType.swift */,
B14B17592462C68F00C2751E /* KeyVerificationManuallyVerifyCoordinator.swift */,
B14B17582462C68F00C2751E /* KeyVerificationManuallyVerifyViewAction.swift */,
B14B175F2462C68F00C2751E /* KeyVerificationManuallyVerifyViewState.swift */,
B14B175C2462C68F00C2751E /* KeyVerificationManuallyVerifyViewModelType.swift */,
B14B175D2462C68F00C2751E /* KeyVerificationManuallyVerifyViewModel.swift */,
B14B175A2462C68F00C2751E /* KeyVerificationManuallyVerifyViewController.swift */,
B14B175B2462C68F00C2751E /* KeyVerificationManuallyVerifyViewController.storyboard */,
);
path = ManuallyVerify;
sourceTree = "<group>";
};
B14F142522144F6400FA0595 /* RecoveryKey */ = {
isa = PBXGroup;
children = (
@ -2780,6 +2811,7 @@
B18DEDAB243372560075FEF7 /* SelfVerifyWait */,
324A2046225FC571004FE8B0 /* Incoming */,
3232AB96225730E100AD6A5C /* Start */,
B14B17572462C68F00C2751E /* ManuallyVerify */,
);
path = Device;
sourceTree = "<group>";
@ -4704,6 +4736,7 @@
B1B5583D20EF6E7F00210D55 /* GroupRoomTableViewCell.xib in Resources */,
B1B5572D20EE6C4D00210D55 /* RoomParticipantsViewController.xib in Resources */,
32A6001C22C661100042C1D9 /* EditHistoryViewController.storyboard in Resources */,
B14B17632462C69000C2751E /* KeyVerificationManuallyVerifyViewController.storyboard in Resources */,
B1B5577220EE702800210D55 /* JitsiViewController.xib in Resources */,
B1B557D720EF5EA900210D55 /* RoomActivitiesView.xib in Resources */,
B1098BF821ECFE65000DDA48 /* KeyBackupSetupPassphraseViewController.storyboard in Resources */,
@ -5021,6 +5054,7 @@
F083BDEE1E7009ED00A9B29C /* MXRoom+Riot.m in Sources */,
B120863722EF375F001F89E0 /* ReactionHistoryBridgeCoordinatorPresenter.swift in Sources */,
B1B5598620EFC3E000210D55 /* RiotSettings.swift in Sources */,
B14B17622462C69000C2751E /* KeyVerificationManuallyVerifyViewController.swift in Sources */,
B1C960F02458308D00C5704B /* RoundedButton.swift in Sources */,
B1CE83D52422817200D07506 /* KeyVerificationVerifyByScanningViewController.swift in Sources */,
3232ABA3225730E100AD6A5C /* DeviceVerificationStartCoordinatorType.swift in Sources */,
@ -5082,6 +5116,8 @@
B125FE1D231D5DE400B72806 /* SettingsDiscoveryViewModel.swift in Sources */,
32863A5A2384070300D07C4A /* RiotSharedSettings.swift in Sources */,
B1B5594720EF7BD000210D55 /* RoomCollectionViewCell.m in Sources */,
B14B17652462C69000C2751E /* KeyVerificationManuallyVerifyViewModel.swift in Sources */,
B14B17662462C69000C2751E /* KeyVerificationManuallyVerifyCoordinatorType.swift in Sources */,
B10CFBC32268D99D00A5842E /* JitsiService.swift in Sources */,
B1A6C10B23882B6C002882FD /* SlidingModalPresentationAnimator.swift in Sources */,
B1B558C120EF768F00210D55 /* RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.m in Sources */,
@ -5310,6 +5346,7 @@
B1B558D020EF768F00210D55 /* RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.m in Sources */,
B1B558CF20EF768F00210D55 /* RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.m in Sources */,
B140B4A221F87F7100E3F5FE /* OperationQueue.swift in Sources */,
B14B17612462C69000C2751E /* KeyVerificationManuallyVerifyCoordinator.swift in Sources */,
B183226C23F59F810035B2E8 /* CloseButton.swift in Sources */,
B1B5575120EE6C4D00210D55 /* AuthenticationViewController.m in Sources */,
B1CE83BA2422815C00D07506 /* KeyVerificationService.swift in Sources */,
@ -5411,6 +5448,7 @@
6E6F1CAA244DC1E90068B78B /* SectionHeaderView.m in Sources */,
B1B558EE20EF768F00210D55 /* RoomOutgoingAttachmentBubbleCell.m in Sources */,
32BF994F21FA29A400698084 /* SettingsKeyBackupViewModel.swift in Sources */,
B14B17602462C69000C2751E /* KeyVerificationManuallyVerifyViewAction.swift in Sources */,
B190F55D22CE5A9700AEB493 /* EditHistorySection.swift in Sources */,
32DB557E22FDADE50016329E /* ServiceTermsModalScreenViewAction.swift in Sources */,
32A6002022C66FCF0042C1D9 /* EditHistoryMessage.swift in Sources */,
@ -5436,10 +5474,12 @@
B16932E720F3C37100746532 /* HomeMessagesSearchDataSource.m in Sources */,
B12D79FF23E2462200FACEDC /* UserVerificationStartViewState.swift in Sources */,
B1B558CE20EF768F00210D55 /* RoomOutgoingEncryptedAttachmentBubbleCell.m in Sources */,
B14B17672462C69000C2751E /* KeyVerificationManuallyVerifyViewState.swift in Sources */,
B1B5577D20EE84BF00210D55 /* CircleButton.m in Sources */,
32607D6D243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyCoordinatorType.swift in Sources */,
32BF995521FA2AB700698084 /* SettingsKeyBackupViewAction.swift in Sources */,
B109D6F1222D8C400061B6D9 /* UIApplication.swift in Sources */,
B14B17642462C69000C2751E /* KeyVerificationManuallyVerifyViewModelType.swift in Sources */,
B1BEE73723DF44A60003A4CB /* UserVerificationSessionsStatusViewState.swift in Sources */,
B108932823ABEE6800802670 /* BubbleCellReadReceiptsDisplayable.swift in Sources */,
B1B558FF20EF768F00210D55 /* RoomIncomingTextMsgBubbleCell.m in Sources */,

View file

@ -2769,6 +2769,8 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
// Register to new key verification request
[self registerNewRequestNotificationForSession:mxSession];
[self checkLocalPrivateKeysInSession:mxSession];
}
else if (mxSession.state == MXSessionStateClosed)
{
@ -3523,6 +3525,33 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
[eventsToNotify removeObjectForKey:@(mxSession.hash)];
}
- (void)checkLocalPrivateKeysInSession:(MXSession*)mxSession
{
id<MXCryptoStore> cryptoStore = mxSession.crypto.store;
NSUInteger keysCount = 0;
if ([cryptoStore secretWithSecretId:MXSecretId.keyBackup])
{
keysCount++;
}
if ([cryptoStore secretWithSecretId:MXSecretId.crossSigningUserSigning])
{
keysCount++;
}
if ([cryptoStore secretWithSecretId:MXSecretId.crossSigningSelfSigning])
{
keysCount++;
}
if ((keysCount > 0 && keysCount < 3)
|| (mxSession.crypto.crossSigning.canTrustCrossSigning && !mxSession.crypto.crossSigning.canCrossSign))
{
// We should have 3 of them. If not, request them again as mitigation
NSLog(@"[AppDelegate] checkLocalPrivateKeysInSession: request keys because keysCount = %@", @(keysCount));
[mxSession.crypto requestAllPrivateKeys];
}
}
#pragma mark -
/**

View file

@ -303,7 +303,7 @@
<!--Settings-->
<scene sceneID="9we-7Q-LBo">
<objects>
<tableViewController title="Settings" id="taU-5Q-sdv" customClass="SettingsViewController" sceneMemberID="viewController">
<tableViewController storyboardIdentifier="SettingsViewController" title="Settings" id="taU-5Q-sdv" customClass="SettingsViewController" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="interactive" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="egL-pK-Xhr">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@ -555,15 +555,16 @@
<image name="logo" width="120" height="101"/>
<image name="search_icon" width="22" height="22"/>
<image name="settings_icon" width="24" height="24"/>
<image name="tab_favourites" width="25" height="25"/>
<image name="tab_favourites_selected" width="25" height="25"/>
<image name="tab_groups" width="25" height="25"/>
<image name="tab_groups_selected" width="25" height="25"/>
<image name="tab_home" width="25" height="25"/>
<image name="tab_home_selected" width="25" height="25"/>
<image name="tab_people" width="25" height="25"/>
<image name="tab_people_selected" width="25" height="25"/>
<image name="tab_rooms" width="25" height="25"/>
<image name="tab_favourites" width="30" height="30"/>
<image name="tab_favourites_selected" width="30" height="30"/>
<image name="tab_groups" width="30" height="30"/>
<image name="tab_groups_selected" width="30" height="30"/>
<image name="tab_home" width="30" height="30"/>
<image name="tab_home_selected" width="30" height="30"/>
<image name="tab_people" width="30" height="30"/>
<image name="tab_people_selected" width="30" height="30"/>
<image name="tab_rooms" width="30" height="30"/>
<image name="tab_rooms_selected" width="30" height="30"/>
</resources>
<inferredMetricsTieBreakers>
<segue reference="bwO-oZ-2vj"/>

View file

@ -955,3 +955,14 @@
"security_settings_title" = "Сигурност";
"security_settings_crypto_sessions" = "МОИТЕ СЕСИИ";
"security_settings_crypto_sessions_loading" = "Зареждан на сесии…";
// MARK: Clients
"client_desktop_name" = "Riot Desktop";
"client_web_name" = "Riot Web";
"client_ios_name" = "Riot iOS";
"client_android_name" = "Riot X за Android";
"room_member_power_level_admin_in" = "Админ в %@";
"room_member_power_level_moderator_in" = "Модератор в %@";
"room_member_power_level_custom_in" = "Собствен (%@) в %@";
"room_member_power_level_short_admin" = "Админ";
"room_member_power_level_short_moderator" = "Модератор";
"room_member_power_level_short_custom" = "Собствен";

View file

@ -1074,6 +1074,12 @@
"key_verification_self_verify_current_session_alert_message" = "Other users may not trust it.";
"key_verification_self_verify_current_session_alert_validate_action" = "Verify";
// Unverified sessions
"key_verification_self_verify_unverified_sessions_alert_title" = "Review where you're logged in";
"key_verification_self_verify_unverified_sessions_alert_message" = "Verify all your sessions to ensure your account & messages are safe.";
"key_verification_self_verify_unverified_sessions_alert_validate_action" = "Review";
// MARK: Self verification wait
"device_verification_self_verify_wait_title" = "Complete security";
@ -1091,6 +1097,16 @@
"key_verification_verify_sas_additional_information" = "For ultimate security, use another trusted means of communication or do this in person.";
// MARK: Manually Verify Device
"key_verification_manually_verify_device_title" = "Manually Verify by Text";
"key_verification_manually_verify_device_instruction" = "Confirm by comparing the following with the User Settings in your other session:";
"key_verification_manually_verify_device_name_title" = "Session name";
"key_verification_manually_verify_device_id_title" = "Session ID";
"key_verification_manually_verify_device_key_title" = "Session key";
"key_verification_manually_verify_device_additional_information" = "If they don't match, the security of your communication may be compromised.";
"key_verification_manually_verify_device_validate_action" = "Verify";
// Device
"device_verification_verify_wait_partner" = "Waiting for partner to confirm…";
@ -1232,6 +1248,7 @@
"key_verification_verify_qr_code_title" = "Verify by scanning";
"key_verification_verify_qr_code_information" = "Scan the code to securely verify each other.";
"key_verification_verify_qr_code_information_other_device" = "Scan the code below to verify:";
"key_verification_verify_qr_code_emoji_information" = "Verify by comparing unique emoji.";
"key_verification_verify_qr_code_scan_code_action" = "Scan their code";
"key_verification_verify_qr_code_cannot_scan_action" = "Can't scan?";
@ -1277,7 +1294,7 @@
// Session details
"user_verification_session_details_trusted_title" = "Trusted";
"user_verification_session_details_untrusted_title" = "Warning";
"user_verification_session_details_untrusted_title" = "Not Trusted";
"user_verification_session_details_information_trusted_current_user" = "This session is trusted for secure messaging because you verified it:";
"user_verification_session_details_information_trusted_other_user_part1" = "This session is trusted for secure messaging because ";
@ -1289,5 +1306,6 @@
"user_verification_session_details_additional_information_untrusted_other_user" = "Until this user trusts this session, messages sent to and from it are labelled with warnings. Alternatively, you can manually verify it.";
"user_verification_session_details_additional_information_untrusted_current_user" = "If you didnt sign in to this session, your account may be compromised.";
"user_verification_session_details_verify_action_current_user" = "Verify";
"user_verification_session_details_verify_action_current_user" = "Interactively Verify";
"user_verification_session_details_verify_action_current_user_manually" = "Manually Verify by Text";
"user_verification_session_details_verify_action_other_user" = "Manually verify";

View file

@ -1023,8 +1023,8 @@
"security_settings_crosssigning" = "SIGNATURE CROISÉE";
"security_settings_cryptography" = "CRYPTOGRAPHIE";
"room_participants_action_security_status_loading" = "Chargement…";
"device_verification_self_verify_alert_title" = "Nouvelle connexion";
"device_verification_self_verify_alert_message" = "Utilisez cette session pour vérifier la nouvelle, ce qui lui permettra daccéder aux messages chiffrés : %@\nSi vous ne vous êtes pas connecté à cette session, votre compte est peut-être compromis.";
"device_verification_self_verify_alert_title" = "Nouvelle connexion. Était-ce vous ?";
"device_verification_self_verify_alert_message" = "Vérifiez la nouvelle connexion pour accéder à votre compte : %@";
"device_verification_self_verify_alert_cancel_action" = "Ce nétait pas moi";
"device_verification_self_verify_start_verify_action" = "Commencer la vérification";
"device_verification_self_verify_start_information" = "Utilisez cette session pour vérifier la nouvelle, ce qui lui permettra daccéder aux messages chiffrés.";
@ -1067,3 +1067,29 @@
"client_android_name" = "Riot X pour Android";
"device_verification_self_verify_wait_new_sign_in_title" = "Vérifier cette connexion";
"device_verification_self_verify_wait_additional_information" = "ou un autre client Matrix qui prend en charge la signature croisée";
// MARK: - Device Verification
"key_verification_other_session_title" = "Vérifier la session";
"key_verification_new_session_title" = "Vérifiez votre nouvelle session";
"key_verification_this_session_title" = "Vérifier cette session";
"device_verification_security_advice_emoji" = "Comparez les émojis uniques, en vérifiant quils apparaissent bien dans le même ordre.";
"device_verification_security_advice_number" = "Comparez les nombres, en vérifiant quils apparaissent bien dans le même ordre.";
"key_verification_verify_sas_title_emoji" = "Comparer les émojis";
"key_verification_verify_sas_title_number" = "Comparer les nombres";
"key_verification_verify_sas_cancel_action" = "Ils ne correspondent pas";
"key_verification_verify_sas_validate_action" = "Ils correspondent";
"key_verification_verify_sas_additional_information" = "Pour une sécurité optimale, utilisez un autre moyen de communication fiable ou faites cela en personne.";
"key_verification_verified_new_session_title" = "Nouvelle session vérifiée !";
"key_verification_verified_other_session_information" = "Vous pouvez à présent lire les messages sécurisés sur votre autre session, et les autres utilisateurs sauront quils peuvent lui faire confiance.";
"key_verification_verified_new_session_information" = "Vous pouvez à présent lire les messages sécurisés sur votre nouvel appareil et les autres utilisateurs sauront quils peuvent lui faire confiance.";
"key_verification_verified_this_session_information" = "Vous pouvez à présent lire les messages sécurisés sur cet appareil et les autres utilisateurs sauront quils peuvent lui faire confiance.";
"key_verification_verified_user_information" = "Les messages avec cet utilisateurs sont chiffrés de bout en bout et ne peuvent être lus par des tiers.";
"key_verification_verify_qr_code_emoji_information" = "Vérifier en comparant des émojis uniques.";
"key_verification_verify_qr_code_start_emoji_action" = "Vérifier par émojis";
"device_verification_self_verify_alert_validate_action" = "Vérifier";
"key_verification_self_verify_current_session_alert_title" = "Vérifier cette session";
"key_verification_self_verify_current_session_alert_message" = "Les autres utilisateurs peuvent ne pas lui faire confiance.";
"key_verification_self_verify_current_session_alert_validate_action" = "Vérifier";
"key_verification_self_verify_unverified_sessions_alert_title" = "Vérifiez où vous vous êtes connecté";
"key_verification_self_verify_unverified_sessions_alert_message" = "Vérifiez toutes vos sessions pour vous assurer que votre compte et vos message sont en sécurité.";
"key_verification_self_verify_unverified_sessions_alert_validate_action" = "Vérifier";
"key_verification_verify_qr_code_information_other_device" = "Scannez le code ci-dessous pour vérifier :";

View file

@ -984,7 +984,7 @@
"room_participants_security_loading" = "Betöltés…";
"room_participants_security_information_room_not_encrypted" = "Az üzenetek a szobában nincsenek végponttól végpontig titkosítva.";
"room_participants_security_information_room_encrypted" = "A szobában az üzenetek végponttól végpontig titkosítva vannak.\n\nAz üzeneteidet lakattal vannak biztosítva és csak neked és a címzetteknek van meg a kulcs hozzá.";
"key_verification_user_title" = "Felhasználó ellenőrzése";
"key_verification_user_title" = "Ezek ellenőrzése";
"key_verification_verify_user_title_emoji" = "Hitelesítheted a felhasználót, ha megerősíted, hogy az alábbi egyedi emoji-k azok amik megjelentek a képernyőjén.";
"key_verification_verify_user_title_number" = "Hitelesítheted a felhasználót, ha megerősíted, hogy az alábbi számok jelentek meg az ő képernyőjén is.";
"key_verification_verified_user_description_1" = "Sikeresen ellenőrizted ezt a felhasználót.";
@ -1034,8 +1034,8 @@
"room_member_power_level_short_custom" = "Egyedi";
// Recover from private key
"key_backup_recover_from_private_key_info" = "Mentés visszaállítás…";
"device_verification_self_verify_alert_title" = "Új Bejelentkezés";
"device_verification_self_verify_alert_message" = "Használd ezt a munkamenetet az új ellenőrzéséhez, amivel hozzáférést biztosíthatsz a titkosított üzenethez: %@\nHa nem te jelentkeztél be ebbe a munkamenetbe akkor lehetséges, hogy a fiókodat feltörték.";
"device_verification_self_verify_alert_title" = "Új bejelentkezés. Ez te vagy?";
"device_verification_self_verify_alert_message" = "Ellenőrizd ezt az új bejelentkezést ami hozzáfér a fiókodhoz: %@";
"device_verification_self_verify_alert_cancel_action" = "Nem én voltam";
"device_verification_self_verify_start_verify_action" = "Ellenőrzés elindítása";
"device_verification_self_verify_start_information" = "Az új munkamenet ellenőrzéséhez használd ezt, amivel hozzáférést adsz a titkosított üzenetekhez.";
@ -1069,3 +1069,29 @@
"security_settings_coming_soon" = "Bocsánat. Riot-iOS-n ez a művelet egyenlőre nem érhető el. Kérlek használj másik Matrix klienst a beállításához. Riot-iOS használni fogja.";
"device_verification_self_verify_wait_new_sign_in_title" = "Belépés ellenőrzése";
"device_verification_self_verify_wait_additional_information" = "vagy másik eszközök közötti hitelesítésre alkalmas Matrix kliensre";
// MARK: - Device Verification
"key_verification_other_session_title" = "Munkamenet hitelesítése";
"key_verification_new_session_title" = "Új munkamenet ellenőrzése";
"key_verification_this_session_title" = "Munkamenet ellenőrzése";
"device_verification_security_advice_emoji" = "Hasonlítsd össze ezeket az egyedi emodzsikat és győződj meg arról, hogy ugyanabban a sorrendben jelentek meg.";
"device_verification_security_advice_number" = "Hasonlítsd össze a számokat, győződj meg arról, hogy ugyanabban a sorrendben jelennek meg.";
"device_verification_self_verify_alert_validate_action" = "Ellenőriz";
"key_verification_self_verify_current_session_alert_title" = "Munkamenet ellenőrzése";
"key_verification_self_verify_current_session_alert_message" = "Más felhasználók lehet, hogy nem bíznak benne.";
"key_verification_self_verify_current_session_alert_validate_action" = "Ellenőriz";
"key_verification_verify_sas_title_emoji" = "Emodzsik összehasonlítása";
"key_verification_verify_sas_title_number" = "Számok összehasonlítása";
"key_verification_verify_sas_cancel_action" = "Nem egyeznek";
"key_verification_verify_sas_validate_action" = "Egyeznek";
"key_verification_verify_sas_additional_information" = "A legnagyobb biztonság érdekében használj megbízható kommunikációs csatornát vagy tedd meg személyesen.";
"key_verification_verified_new_session_title" = "Új munkamenet hitelesítve!";
"key_verification_verified_other_session_information" = "A másik munkamenetekben is el tudod olvasni a titkosított üzeneteket és más felhasználók tudni fogják, hogy megbízhatnak benne.";
"key_verification_verified_new_session_information" = "Az új eszközödön is el tudod olvasni a titkosított üzeneteket és más felhasználók tudni fogják, hogy megbízhatnak benne.";
"key_verification_verified_this_session_information" = "Ezen az eszközödön is el tudod olvasni a titkosított üzeneteket és más felhasználók tudni fogják, hogy megbízhatnak benne.";
"key_verification_verified_user_information" = "Az üzenetek ezzel a felhasználóval a végpontok között titkosítva vannak és más nem tudja elolvasni.";
"key_verification_verify_qr_code_emoji_information" = "Ellenőrzés egyedi emodzsik összehasonlításával.";
"key_verification_verify_qr_code_start_emoji_action" = "Ellenőrzés emodzsival";
"key_verification_self_verify_unverified_sessions_alert_title" = "Tekintsd át hol vagy bejelentkezve";
"key_verification_self_verify_unverified_sessions_alert_message" = "Ellenőrizd minden munkamenetedet, hogy a fiókod és az üzeneteid biztonságban legyenek.";
"key_verification_self_verify_unverified_sessions_alert_validate_action" = "Átnézés";
"key_verification_verify_qr_code_information_other_device" = "Ellenőrzéshez olvasd be a kódot alább:";

View file

@ -952,7 +952,7 @@
"room_participants_action_security_status_verify" = "Verifica";
"room_participants_action_security_status_warning" = "Attenzione";
"room_participants_security_loading" = "Caricamento…";
"key_verification_user_title" = "verificale";
"key_verification_user_title" = "Verificale";
"room_participants_security_information_room_not_encrypted" = "I messaggi in questa stanza non sono cifrati end-to-end.";
"room_participants_security_information_room_encrypted" = "I messaggi in questa stanza sono cifrati end-to-end.\n\nI tuoi messaggi sono protetti con lucchetti e solo te ed il destinatario avete le chiavi univoche per sbloccarli.";
"key_verification_verify_user_title_emoji" = "Verifica questo utente confermando che le seguenti emoji appaiono sul suo schermo, nello stesso ordine.";
@ -995,8 +995,8 @@
"security_settings_crosssigning" = "FIRMA INCROCIATA";
"security_settings_cryptography" = "CRITTOGRAFIA";
"room_participants_action_security_status_loading" = "Caricamento…";
"device_verification_self_verify_alert_title" = "Nuovo accesso";
"device_verification_self_verify_alert_message" = "Usa questa sessione per verificare quella nuova, dandole l'accesso ai messaggi cifrati: %@\nSe non hai fatto l'accesso a questa sessione, il tuo account potrebbe essere compromesso.";
"device_verification_self_verify_alert_title" = "Nuovo accesso. Eri tu?";
"device_verification_self_verify_alert_message" = "Verifica il nuovo accesso entrando nel tuo account: %@";
"device_verification_self_verify_alert_cancel_action" = "Non ero io";
"device_verification_self_verify_start_verify_action" = "Inizia la verifica";
"device_verification_self_verify_start_information" = "Usa questa sessione per verificare quella nuova, dandole l'accesso ai messaggi cifrati.";
@ -1047,3 +1047,23 @@
"device_verification_security_advice_number" = "Confronta i numeri, assicurandoti che compaiono nello stesso ordine.";
"key_verification_verify_title_emoji" = "Confronta emoji";
"key_verification_verify_title_number" = "Confronta numeri";
"device_verification_self_verify_alert_validate_action" = "Verifica";
"key_verification_self_verify_current_session_alert_title" = "Verifica questa sessione";
"key_verification_self_verify_current_session_alert_message" = "Altri utenti potrebbero non fidarsi.";
"key_verification_self_verify_current_session_alert_validate_action" = "Verifica";
"key_verification_verify_sas_title_emoji" = "Confronta emoji";
"key_verification_verify_sas_title_number" = "Confronta numeri";
"key_verification_verify_sas_cancel_action" = "Non corrispondono";
"key_verification_verify_sas_validate_action" = "Corrispondono";
"key_verification_verify_sas_additional_information" = "Per la massima sicurezza, usate un altro mezzo di comunicazione fidato o fatelo di persona.";
"key_verification_verified_new_session_title" = "Nuova sessione verificata!";
"key_verification_verified_other_session_information" = "Ora puoi leggere i messaggi sicuri nell'altra tua sessione e gli altri utenti sapranno che si possono fidare.";
"key_verification_verified_new_session_information" = "Ora puoi leggere i messaggi sicuri nell'altro tuo dispositivo e gli altri utenti sapranno che si possono fidare.";
"key_verification_verified_this_session_information" = "Ora puoi leggere i messaggi sicuri in questo dispositivo e gli altri utenti sapranno che si possono fidare.";
"key_verification_verified_user_information" = "I messaggi con questo utente sono cifrati end-to-end e non possono essere letti da terze parti.";
"key_verification_verify_qr_code_emoji_information" = "Verifica confrontando emoji univoci.";
"key_verification_verify_qr_code_start_emoji_action" = "Verifica con emoji";
"key_verification_self_verify_unverified_sessions_alert_title" = "Controlla dove hai fatto l'accesso";
"key_verification_self_verify_unverified_sessions_alert_message" = "Verifica tutte le tue sessioni per assicurarti che l'account e i messaggi siano protetti.";
"key_verification_self_verify_unverified_sessions_alert_validate_action" = "Controlla";
"key_verification_verify_qr_code_information_other_device" = "Scansiona il codice sotto per verificare:";

View file

@ -976,7 +976,7 @@
"manage_session_trusted" = "Besuar prej jush";
"manage_session_not_trusted" = "Jo i besuar";
"manage_session_sign_out" = "Dilni nga ky sesion";
"key_verification_user_title" = "Verifikoni përdoruesin";
"key_verification_user_title" = "Verifikojini";
"key_verification_verify_user_title_emoji" = "Verifikojeni këtë përdorues duke ripohuar se <em>emoji</em> unik vijues shfaqet në ekranin e tij, në të njëjtën radhë.";
"key_verification_verify_user_title_number" = "Verifikojeni këtë përdorues duke ripohuar se numrat vijues shfaqen në ekranin e tij, në të njëjtën radhë.";
"key_verification_verified_user_description_1" = "E verifikuat me sukses këtë përdorues.";
@ -1016,20 +1016,70 @@
"key_verification_verify_qr_code_scan_other_code_success_message" = "Kodi QR u vlerësua me sukses.";
"skip" = "Anashkaloje";
"room_participants_action_security_status_loading" = "Po ngarkohet…";
"device_verification_self_verify_alert_title" = "Hyrje e Re";
"device_verification_self_verify_alert_message" = "Përdoreni këtë sesion që të verifikoni atë të riun tuaj, duke i akorduar hyrje te mesazhe të fshehtëzuar: %@\nNëse hyrjen te ky sesion se keni bërë ju, llogaria juaj mund të jetë komprometuar.";
"device_verification_self_verify_alert_title" = "Hyrje e re. Ju qetë?";
"device_verification_self_verify_alert_message" = "Verifikoni kredencialet e reja për hyrje te llogaria juaj: %@";
"device_verification_self_verify_alert_cancel_action" = "Ky sqeshë unë";
"device_verification_self_verify_start_verify_action" = "Fillo verifikimin";
"device_verification_self_verify_start_information" = "Përdoreni këtë sesion që të verifikoni atë të riun tuaj, duke i akorduar hyrje te mesazhe të fshehtëzuar.";
"device_verification_self_verify_start_waiting" = "Po pritet…";
"device_verification_self_verify_wait_title" = "Siguri e plotë";
"device_verification_self_verify_wait_information" = "Përdorni një sesion ekzistues që të verifikoni këtë të riun, duke i akorduar hyrje te mesazhe të fshehtëzuar.";
"device_verification_self_verify_wait_information" = "Verifikoni këtë sesion prej një nga sesionet tuaj të tjera, duke i akorduar hyrje te mesazhe të fshehtëzuar.\n\nPërdorni Riot-in më të ri në pajisjet tuaja të tjera:";
"device_verification_self_verify_wait_waiting" = "Po pritet…";
"room_member_power_level_admin_in" = "Përgjegjës te %@";
"room_member_power_level_moderator_in" = "Moderator te %@";
"room_member_power_level_custom_in" = "Vetjak (%@) te %@";
"room_member_power_level_short_admin" = "Përgjegjës";
"room_member_power_level_short_moderator" = "Mod";
"room_member_power_level_short_moderator" = "Moderator";
"room_member_power_level_short_custom" = "Vetjak";
// Recover from private key
"key_backup_recover_from_private_key_info" = "Po rikthehet kopjeruajtje…";
// MARK: Clients
"client_desktop_name" = "Riot Desktop";
"client_web_name" = "Riot Web";
"client_ios_name" = "Riot iOS";
"client_android_name" = "Riot X për Android";
"room_participants_action_security_status_complete_security" = "Siguri e plotë";
"security_settings_crosssigning_info_not_bootstrapped" = "<em>Cross-signing</em> sështë ujdisur ende.";
"security_settings_crosssigning_info_exists" = "Llogaria juaj ka një identitet <em>cross-signing</em>, por sështë ende i besuar nga ky sesion. Plotësoni sigurinë e këtij sesioni.";
"security_settings_crosssigning_info_trusted" = "<em>Cross-signing</em> është i aktivizuar. Mund të besoni përdorues të tjerë dhe sesionet tuaj të tjerë bazuar në <em>cross-signing</em>, por smund të kryeni <em>cross-sign</em> që nga ky sesion,ngaqë nuk ka kyçe privatë për <em>cross-signing</em>. Plotësoni sigurinë e këtij sesioni.";
"security_settings_crosssigning_info_ok" = "<em>Cross-signing</em> është i aktivizuar.";
"security_settings_crosssigning_complete_security" = "Siguri e plotë";
"security_settings_complete_security_alert_title" = "Siguri e plotë";
"security_settings_complete_security_alert_message" = "Së pari duhet të plotësoni sigurinë në sesionin tuaj të tanishëm.";
"security_settings_coming_soon" = "Na ndjeni. Ky veprim sështë ende pjesë e Riot-iOS-it. Ju lutemi, për ta pasur, përdorni një klient tjetër Matrix. Riot-iOS-i do ta përdorë.";
// MARK: - Device Verification
"key_verification_other_session_title" = "Verifiko sesion";
"key_verification_new_session_title" = "Verifikoni sesionin tuaj të ri";
"key_verification_this_session_title" = "Verifikoni këtë sesion";
"device_verification_security_advice_emoji" = "Krahasoni emoji-n unik, duke u siguruar se shfaqen në të njëjtën radhë.";
"device_verification_security_advice_number" = "Krahasoni numrat, duke u siguruar se shfaqen në të njëjtën radhë.";
"device_verification_self_verify_alert_validate_action" = "Verifikoje";
"key_verification_self_verify_current_session_alert_title" = "Verifikoni këtë sesion";
"key_verification_self_verify_current_session_alert_message" = "Përdorues të tjerë mund të mos e besojnë.";
"key_verification_self_verify_current_session_alert_validate_action" = "Verifikoje";
"key_verification_self_verify_unverified_sessions_alert_title" = "Shqyrtojini kur të jeni i futur";
"key_verification_self_verify_unverified_sessions_alert_message" = "Verifikoni krejt sesionet tuaj që të siguroheni se llogaria & mesazhet tuaja janë të sigurt.";
"key_verification_self_verify_unverified_sessions_alert_validate_action" = "Shqyrtojeni";
"device_verification_self_verify_wait_new_sign_in_title" = "Verifikoni këto kredenciale hyrjeje";
"device_verification_self_verify_wait_additional_information" = "ose një tjetër klient Matrix i aftë për <em>cross-signing</em";
"key_verification_verify_sas_title_emoji" = "Krahasoni emoji";
"key_verification_verify_sas_title_number" = "Krahasoni numra";
"key_verification_verify_sas_cancel_action" = "Spërputhen";
"key_verification_verify_sas_validate_action" = "Përputhen";
"key_verification_verify_sas_additional_information" = "Për sigurinë përfundimtare, përdorni mjete të tjera të besuara komunikimi ose bëjeni këtë personalisht.";
"key_verification_verified_new_session_title" = "U verifikua sesion i ri!";
"key_verification_verified_other_session_information" = "Tani mund të lexoni mesazhe të sigurt në sesionin tuaj tjetër, dhe përdorues të tjerë do ta dinë se mund ti besojnë.";
"key_verification_verified_new_session_information" = "Tani mund të lexoni mesazhe të sigurt në pajisjen tuaj të re, dhe përdorues të tjerë do ta dinë se mund ti besojnë.";
"key_verification_verified_this_session_information" = "Tani mund të lexoni mesazhe të sigurt në këtë pajisje, dhe përdorues të tjerë do ta dinë se mund ti besojnë.";
"key_verification_verified_user_information" = "Mesazhet me këtë përdorues fshehtëzohen skaj-më-skaj dhe smund të lexohen nga palë të treta.";
"key_verification_verify_qr_code_information_other_device" = "Për ta verifikuar, skanoni kodin më poshtë:";
"key_verification_verify_qr_code_emoji_information" = "Verifikoje duke krahasuar emoji unik.";
"key_verification_verify_qr_code_start_emoji_action" = "Verifikojeni përmes emoji-t";
// Scanning
"key_verification_scan_confirmation_scanning_title" = "Thuajse mbërritëm! Po pritet për ripohim…";
"key_verification_scan_confirmation_scanning_user_waiting_other" = "Po pritet për %@…";
"key_verification_scan_confirmation_scanning_device_waiting_other" = "Po pritet për pajisje tjetër…";
// Scanned
"key_verification_scan_confirmation_scanned_title" = "Thuajse mbërritëm!";
"key_verification_scan_confirmation_scanned_user_information" = "A shfaq %@ të njëjtën mburojë?";
"key_verification_scan_confirmation_scanned_device_information" = "A shfaq pajisja juaj tjetër të njëjtën mburojë?";

View file

@ -28,4 +28,13 @@ extension UILabel {
self.attributedText = attributeString
}
// Fix multiline label height with auto layout. After performing orientation multiline label text appears on one line. For more information see https://www.objc.io/issues/3-views/advanced-auto-layout-toolbox/#intrinsic-content-size-of-multi-line-text
@objc func vc_fixMultilineHeight() {
let width = self.frame.size.width
if self.preferredMaxLayoutWidth != width {
self.preferredMaxLayoutWidth = width
}
}
}

View file

@ -20,7 +20,7 @@ extension UIViewController {
/// Remove back bar button title when pushing a view controller.
/// This method should be called on the previous controller in UINavigationController stack.
func vc_removeBackTitle() {
@objc func vc_removeBackTitle() {
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
}

View file

@ -77,6 +77,11 @@ internal enum StoryboardScene {
internal static let initialScene = InitialSceneType<Riot.KeyVerificationDataLoadingViewController>(storyboard: KeyVerificationDataLoadingViewController.self)
}
internal enum KeyVerificationManuallyVerifyViewController: StoryboardType {
internal static let storyboardName = "KeyVerificationManuallyVerifyViewController"
internal static let initialScene = InitialSceneType<Riot.KeyVerificationManuallyVerifyViewController>(storyboard: KeyVerificationManuallyVerifyViewController.self)
}
internal enum KeyVerificationScanConfirmationViewController: StoryboardType {
internal static let storyboardName = "KeyVerificationScanConfirmationViewController"

View file

@ -1526,6 +1526,34 @@ internal enum VectorL10n {
internal static func keyVerificationIncomingRequestIncomingAlertMessage(_ p1: String) -> String {
return VectorL10n.tr("Vector", "key_verification_incoming_request_incoming_alert_message", p1)
}
/// If they don't match, the security of your communication may be compromised.
internal static var keyVerificationManuallyVerifyDeviceAdditionalInformation: String {
return VectorL10n.tr("Vector", "key_verification_manually_verify_device_additional_information")
}
/// Session ID
internal static var keyVerificationManuallyVerifyDeviceIdTitle: String {
return VectorL10n.tr("Vector", "key_verification_manually_verify_device_id_title")
}
/// Confirm by comparing the following with the User Settings in your other session:
internal static var keyVerificationManuallyVerifyDeviceInstruction: String {
return VectorL10n.tr("Vector", "key_verification_manually_verify_device_instruction")
}
/// Session key
internal static var keyVerificationManuallyVerifyDeviceKeyTitle: String {
return VectorL10n.tr("Vector", "key_verification_manually_verify_device_key_title")
}
/// Session name
internal static var keyVerificationManuallyVerifyDeviceNameTitle: String {
return VectorL10n.tr("Vector", "key_verification_manually_verify_device_name_title")
}
/// Manually Verify by Text
internal static var keyVerificationManuallyVerifyDeviceTitle: String {
return VectorL10n.tr("Vector", "key_verification_manually_verify_device_title")
}
/// Verify
internal static var keyVerificationManuallyVerifyDeviceValidateAction: String {
return VectorL10n.tr("Vector", "key_verification_manually_verify_device_validate_action")
}
/// Verify your new session
internal static var keyVerificationNewSessionTitle: String {
return VectorL10n.tr("Vector", "key_verification_new_session_title")
@ -1570,6 +1598,18 @@ internal enum VectorL10n {
internal static var keyVerificationSelfVerifyCurrentSessionAlertValidateAction: String {
return VectorL10n.tr("Vector", "key_verification_self_verify_current_session_alert_validate_action")
}
/// Verify all your sessions to ensure your account & messages are safe.
internal static var keyVerificationSelfVerifyUnverifiedSessionsAlertMessage: String {
return VectorL10n.tr("Vector", "key_verification_self_verify_unverified_sessions_alert_message")
}
/// Review where you're logged in
internal static var keyVerificationSelfVerifyUnverifiedSessionsAlertTitle: String {
return VectorL10n.tr("Vector", "key_verification_self_verify_unverified_sessions_alert_title")
}
/// Review
internal static var keyVerificationSelfVerifyUnverifiedSessionsAlertValidateAction: String {
return VectorL10n.tr("Vector", "key_verification_self_verify_unverified_sessions_alert_validate_action")
}
/// Verify this session
internal static var keyVerificationThisSessionTitle: String {
return VectorL10n.tr("Vector", "key_verification_this_session_title")
@ -1658,6 +1698,10 @@ internal enum VectorL10n {
internal static var keyVerificationVerifyQrCodeInformation: String {
return VectorL10n.tr("Vector", "key_verification_verify_qr_code_information")
}
/// Scan the code below to verify:
internal static var keyVerificationVerifyQrCodeInformationOtherDevice: String {
return VectorL10n.tr("Vector", "key_verification_verify_qr_code_information_other_device")
}
/// Did the other user successfully scan the QR code?
internal static var keyVerificationVerifyQrCodeOtherScanMyCodeTitle: String {
return VectorL10n.tr("Vector", "key_verification_verify_qr_code_other_scan_my_code_title")
@ -3726,14 +3770,18 @@ internal enum VectorL10n {
internal static var userVerificationSessionDetailsTrustedTitle: String {
return VectorL10n.tr("Vector", "user_verification_session_details_trusted_title")
}
/// Warning
/// Not Trusted
internal static var userVerificationSessionDetailsUntrustedTitle: String {
return VectorL10n.tr("Vector", "user_verification_session_details_untrusted_title")
}
/// Verify
/// Interactively Verify
internal static var userVerificationSessionDetailsVerifyActionCurrentUser: String {
return VectorL10n.tr("Vector", "user_verification_session_details_verify_action_current_user")
}
/// Manually Verify by Text
internal static var userVerificationSessionDetailsVerifyActionCurrentUserManually: String {
return VectorL10n.tr("Vector", "user_verification_session_details_verify_action_current_user_manually")
}
/// Manually verify
internal static var userVerificationSessionDetailsVerifyActionOtherUser: String {
return VectorL10n.tr("Vector", "user_verification_session_details_verify_action_other_user")

View file

@ -33,6 +33,7 @@ final class RiotSettings: NSObject {
static let allowStunServerFallback = "allowStunServerFallback"
static let stunServerFallback = "stunServerFallback"
static let hideVerifyThisSessionAlert = "hideVerifyThisSessionAlert"
static let hideReviewSessionsAlert = "hideReviewSessionsAlert"
}
static let shared = RiotSettings()
@ -144,4 +145,12 @@ final class RiotSettings: NSObject {
UserDefaults.standard.set(newValue, forKey: UserDefaultsKeys.hideVerifyThisSessionAlert)
}
}
var hideReviewSessionsAlert: Bool {
get {
return UserDefaults.standard.bool(forKey: UserDefaultsKeys.hideReviewSessionsAlert)
} set {
UserDefaults.standard.set(newValue, forKey: UserDefaultsKeys.hideReviewSessionsAlert)
}
}
}

View file

@ -69,8 +69,16 @@ final class KeyVerificationDataLoadingViewController: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Hide back button
self.navigationItem.setHidesBackButton(true, animated: animated)
if let navigationController = self.navigationController {
if navigationController.navigationBar.isHidden == true {
self.navigationItem.hidesBackButton = true
// Show navigation bar if needed
navigationController.setNavigationBarHidden(false, animated: animated)
} else {
// Hide back button
self.navigationItem.setHidesBackButton(true, animated: animated)
}
}
}
// MARK: - Private

View file

@ -22,13 +22,13 @@
<rect key="frame" x="0.0" y="20" width="375" height="647"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fyB-h5-5v2">
<rect key="frame" x="0.0" y="0.0" width="375" height="453"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="443"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="D7P-C8-cqw">
<rect key="frame" x="0.0" y="0.0" width="375" height="103"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="113"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="lPc-YT-wnY">
<rect key="frame" x="0.0" y="0.0" width="375" height="103"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="113"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="J1F-ba-sZ7">
<rect key="frame" x="0.0" y="0.0" width="375" height="50"/>
@ -64,10 +64,10 @@
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="SLA-sa-fBw">
<rect key="frame" x="0.0" y="50" width="375" height="53"/>
<rect key="frame" x="0.0" y="50" width="375" height="63"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="253" text="Scan the code to securely verify each other." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="y2w-7m-BE3">
<rect key="frame" x="20" y="15" width="335" height="38"/>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="253" verticalCompressionResistancePriority="751" text="Scan the code to securely verify each other." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="y2w-7m-BE3">
<rect key="frame" x="20" y="20" width="335" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
@ -75,16 +75,17 @@
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="y2w-7m-BE3" firstAttribute="top" secondItem="SLA-sa-fBw" secondAttribute="top" constant="15" id="4Hi-G4-ifY"/>
<constraint firstItem="y2w-7m-BE3" firstAttribute="top" secondItem="SLA-sa-fBw" secondAttribute="top" constant="20" id="4Hi-G4-ifY"/>
<constraint firstAttribute="trailing" secondItem="y2w-7m-BE3" secondAttribute="trailing" constant="20" id="5xb-BK-tXG"/>
<constraint firstAttribute="bottom" secondItem="y2w-7m-BE3" secondAttribute="bottom" id="NIx-Ms-nsQ"/>
<constraint firstAttribute="height" priority="250" id="xbN-ph-dHU"/>
<constraint firstAttribute="bottom" secondItem="y2w-7m-BE3" secondAttribute="bottom" constant="25" id="NIx-Ms-nsQ"/>
<constraint firstAttribute="height" priority="750" id="xbN-ph-dHU"/>
<constraint firstItem="y2w-7m-BE3" firstAttribute="leading" secondItem="SLA-sa-fBw" secondAttribute="leading" constant="20" id="zoQ-Pi-GNl"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstItem="J1F-ba-sZ7" firstAttribute="width" secondItem="lPc-YT-wnY" secondAttribute="width" id="AYv-UT-c0c"/>
<constraint firstItem="SLA-sa-fBw" firstAttribute="width" secondItem="lPc-YT-wnY" secondAttribute="width" id="elW-WH-1hZ"/>
</constraints>
</stackView>
</subviews>
@ -98,13 +99,13 @@
</constraints>
</view>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="bQd-8A-8hf">
<rect key="frame" x="0.0" y="103" width="375" height="350"/>
<rect key="frame" x="0.0" y="113" width="375" height="330"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vrz-UO-PDk">
<rect key="frame" x="0.0" y="0.0" width="375" height="220"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="200"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="NFT-6Y-5rt">
<rect key="frame" x="97.5" y="20" width="180" height="180"/>
<rect key="frame" x="97.5" y="0.0" width="180" height="180"/>
<constraints>
<constraint firstAttribute="width" constant="180" id="X3y-ER-PrC"/>
<constraint firstAttribute="width" secondItem="NFT-6Y-5rt" secondAttribute="height" multiplier="1:1" id="sOD-Bb-lIr"/>
@ -115,11 +116,11 @@
<constraints>
<constraint firstAttribute="bottom" secondItem="NFT-6Y-5rt" secondAttribute="bottom" constant="20" id="0Wi-uC-aoj"/>
<constraint firstItem="NFT-6Y-5rt" firstAttribute="centerX" secondItem="vrz-UO-PDk" secondAttribute="centerX" id="8UT-Ob-m92"/>
<constraint firstItem="NFT-6Y-5rt" firstAttribute="top" secondItem="vrz-UO-PDk" secondAttribute="top" constant="20" id="Sfi-ob-xej"/>
<constraint firstItem="NFT-6Y-5rt" firstAttribute="top" secondItem="vrz-UO-PDk" secondAttribute="top" id="Sfi-ob-xej"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="s4G-bW-EGe">
<rect key="frame" x="0.0" y="220" width="375" height="55"/>
<rect key="frame" x="0.0" y="200" width="375" height="55"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="a4h-x5-COe">
<rect key="frame" x="20" y="0.0" width="335" height="50"/>
@ -146,7 +147,7 @@
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="n73-GU-j8x">
<rect key="frame" x="0.0" y="275" width="375" height="75"/>
<rect key="frame" x="0.0" y="255" width="375" height="75"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bRZ-4Z-DEJ">
<rect key="frame" x="20" y="5" width="335" height="50"/>

View file

@ -189,6 +189,17 @@ final class KeyVerificationVerifyByScanningViewController: UIViewController {
// Update the copy if QR code scanning is not possible at all
self.informationLabel.text = VectorL10n.keyVerificationVerifyQrCodeEmojiInformation
self.cannotScanButton.setTitle(VectorL10n.keyVerificationVerifyQrCodeStartEmojiAction, for: .normal)
} else {
let informationText: String
switch viewData.verificationKind {
case .user:
informationText = VectorL10n.keyVerificationVerifyQrCodeInformation
default:
informationText = VectorL10n.keyVerificationVerifyQrCodeInformationOtherDevice
}
self.informationLabel.text = informationText
}
}

View file

@ -0,0 +1,71 @@
// File created from ScreenTemplate
// $ createScreen.sh KeyVerification/Device/ManuallyVerify KeyVerificationManuallyVerify
/*
Copyright 2020 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import Foundation
import UIKit
final class KeyVerificationManuallyVerifyCoordinator: KeyVerificationManuallyVerifyCoordinatorType {
// MARK: - Properties
// MARK: Private
private let session: MXSession
private var keyVerificationManuallyVerifyViewModel: KeyVerificationManuallyVerifyViewModelType
private let keyVerificationManuallyVerifyViewController: KeyVerificationManuallyVerifyViewController
// MARK: Public
// Must be used only internally
var childCoordinators: [Coordinator] = []
weak var delegate: KeyVerificationManuallyVerifyCoordinatorDelegate?
// MARK: - Setup
init(session: MXSession, deviceId: String, userId: String) {
self.session = session
let keyVerificationManuallyVerifyViewModel = KeyVerificationManuallyVerifyViewModel(session: self.session, deviceId: deviceId, userId: userId)
let keyVerificationManuallyVerifyViewController = KeyVerificationManuallyVerifyViewController.instantiate(with: keyVerificationManuallyVerifyViewModel)
self.keyVerificationManuallyVerifyViewModel = keyVerificationManuallyVerifyViewModel
self.keyVerificationManuallyVerifyViewController = keyVerificationManuallyVerifyViewController
}
// MARK: - Public methods
func start() {
self.keyVerificationManuallyVerifyViewModel.coordinatorDelegate = self
}
func toPresentable() -> UIViewController {
return self.keyVerificationManuallyVerifyViewController
}
}
// MARK: - KeyVerificationManuallyVerifyViewModelCoordinatorDelegate
extension KeyVerificationManuallyVerifyCoordinator: KeyVerificationManuallyVerifyViewModelCoordinatorDelegate {
func keyVerificationManuallyVerifyViewModel(_ viewModel: KeyVerificationManuallyVerifyViewModelType, didVerifiedDeviceWithId deviceId: String, of userId: String) {
self.delegate?.keyVerificationManuallyVerifyCoordinator(self, didVerifiedDeviceWithId: deviceId, of: userId)
}
func keyVerificationManuallyVerifyViewModelDidCancel(_ viewModel: KeyVerificationManuallyVerifyViewModelType) {
self.delegate?.keyVerificationManuallyVerifyCoordinatorDidCancel(self)
}
}

View file

@ -0,0 +1,29 @@
// File created from ScreenTemplate
// $ createScreen.sh KeyVerification/Device/ManuallyVerify KeyVerificationManuallyVerify
/*
Copyright 2020 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import Foundation
protocol KeyVerificationManuallyVerifyCoordinatorDelegate: class {
func keyVerificationManuallyVerifyCoordinator(_ coordinator: KeyVerificationManuallyVerifyCoordinatorType, didVerifiedDeviceWithId deviceId: String, of userId: String)
func keyVerificationManuallyVerifyCoordinatorDidCancel(_ coordinator: KeyVerificationManuallyVerifyCoordinatorType)
}
/// `KeyVerificationManuallyVerifyCoordinatorType` is a protocol describing a Coordinator that handle key backup setup passphrase navigation flow.
protocol KeyVerificationManuallyVerifyCoordinatorType: Coordinator, Presentable {
var delegate: KeyVerificationManuallyVerifyCoordinatorDelegate? { get }
}

View file

@ -0,0 +1,26 @@
// File created from ScreenTemplate
// $ createScreen.sh KeyVerification/Device/ManuallyVerify KeyVerificationManuallyVerify
/*
Copyright 2020 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import Foundation
/// KeyVerificationManuallyVerifyViewController view actions exposed to view model
enum KeyVerificationManuallyVerifyViewAction {
case loadData
case verify
case cancel
}

View file

@ -0,0 +1,232 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="V8j-Lb-PgC">
<device id="retina6_1" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Key Verification Manually Verify View Controller-->
<scene sceneID="mt5-wz-YKA">
<objects>
<viewController extendedLayoutIncludesOpaqueBars="YES" automaticallyAdjustsScrollViewInsets="NO" id="V8j-Lb-PgC" customClass="KeyVerificationManuallyVerifyViewController" customModule="Riot" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="EL9-GA-lwo">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="9U2-KL-ZVA">
<rect key="frame" x="0.0" y="44" width="414" height="852"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="e7g-um-WO4">
<rect key="frame" x="0.0" y="0.0" width="414" height="502"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="voD-3Q-ryt">
<rect key="frame" x="0.0" y="0.0" width="414" height="502"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" text="Confirm by comparing the following with the User Settings in your other session:" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="RIj-L9-tZn">
<rect key="frame" x="20" y="20" width="374" height="33.5"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="12" translatesAutoresizingMaskIntoConstraints="NO" id="qfH-9X-kBZ">
<rect key="frame" x="20" y="73.5" width="374" height="201"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="YcY-tZ-Ga6">
<rect key="frame" x="0.0" y="0.0" width="374" height="59"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Session name" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tp3-dZ-JyO">
<rect key="frame" x="0.0" y="0.0" width="374" height="17"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="14"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="https://riot.im" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9SQ-lH-Hur">
<rect key="frame" x="0.0" y="22" width="374" height="37"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="tp3-dZ-JyO" firstAttribute="top" secondItem="YcY-tZ-Ga6" secondAttribute="top" id="Eai-tB-VyY"/>
<constraint firstAttribute="bottom" secondItem="9SQ-lH-Hur" secondAttribute="bottom" id="MOQ-bv-PAZ"/>
<constraint firstItem="9SQ-lH-Hur" firstAttribute="top" secondItem="tp3-dZ-JyO" secondAttribute="bottom" constant="5" id="RuS-7X-CNf"/>
<constraint firstAttribute="height" priority="250" id="Y0c-6A-FOP"/>
<constraint firstItem="9SQ-lH-Hur" firstAttribute="leading" secondItem="tp3-dZ-JyO" secondAttribute="leading" id="Y9I-6j-wkw"/>
<constraint firstAttribute="trailing" secondItem="tp3-dZ-JyO" secondAttribute="trailing" id="cVj-3V-bmi"/>
<constraint firstItem="tp3-dZ-JyO" firstAttribute="leading" secondItem="YcY-tZ-Ga6" secondAttribute="leading" id="dDq-eF-TRE"/>
<constraint firstItem="9SQ-lH-Hur" firstAttribute="trailing" secondItem="tp3-dZ-JyO" secondAttribute="trailing" id="rzJ-k3-tSZ"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jWK-JI-wHI">
<rect key="frame" x="0.0" y="71" width="374" height="59"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Session ID" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uVC-qK-ET7">
<rect key="frame" x="0.0" y="0.0" width="374" height="17"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="14"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="https://riot.im" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="WHf-qc-H4w">
<rect key="frame" x="0.0" y="22" width="374" height="37"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="uVC-qK-ET7" secondAttribute="trailing" id="Cq3-wf-eMz"/>
<constraint firstAttribute="height" priority="250" id="IhG-aQ-Ez2"/>
<constraint firstItem="WHf-qc-H4w" firstAttribute="top" secondItem="uVC-qK-ET7" secondAttribute="bottom" constant="5" id="Ivk-6g-bPa"/>
<constraint firstItem="WHf-qc-H4w" firstAttribute="trailing" secondItem="uVC-qK-ET7" secondAttribute="trailing" id="MFO-Gp-1oy"/>
<constraint firstItem="uVC-qK-ET7" firstAttribute="top" secondItem="jWK-JI-wHI" secondAttribute="top" id="POZ-uv-KVR"/>
<constraint firstItem="WHf-qc-H4w" firstAttribute="leading" secondItem="uVC-qK-ET7" secondAttribute="leading" id="o6y-OG-KcW"/>
<constraint firstAttribute="bottom" secondItem="WHf-qc-H4w" secondAttribute="bottom" id="pX1-4I-5fr"/>
<constraint firstItem="uVC-qK-ET7" firstAttribute="leading" secondItem="jWK-JI-wHI" secondAttribute="leading" id="qky-qV-dcB"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="EKr-6X-weJ">
<rect key="frame" x="0.0" y="142" width="374" height="59"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Session key" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tBF-i0-Q4C">
<rect key="frame" x="0.0" y="0.0" width="374" height="17"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="14"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="https://riot.im" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5fG-Wi-cVH">
<rect key="frame" x="0.0" y="22" width="374" height="37"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="5fG-Wi-cVH" firstAttribute="leading" secondItem="tBF-i0-Q4C" secondAttribute="leading" id="Kyc-YY-gzQ"/>
<constraint firstAttribute="bottom" secondItem="5fG-Wi-cVH" secondAttribute="bottom" id="ZCc-3Y-ECo"/>
<constraint firstItem="5fG-Wi-cVH" firstAttribute="trailing" secondItem="tBF-i0-Q4C" secondAttribute="trailing" id="Zga-sP-Zc6"/>
<constraint firstItem="5fG-Wi-cVH" firstAttribute="top" secondItem="tBF-i0-Q4C" secondAttribute="bottom" constant="5" id="cr4-9q-O5W"/>
<constraint firstItem="tBF-i0-Q4C" firstAttribute="top" secondItem="EKr-6X-weJ" secondAttribute="top" id="jVr-qa-EU3"/>
<constraint firstAttribute="trailing" secondItem="tBF-i0-Q4C" secondAttribute="trailing" id="mPM-qs-32S"/>
<constraint firstAttribute="height" priority="250" id="sHG-MG-dz7"/>
<constraint firstItem="tBF-i0-Q4C" firstAttribute="leading" secondItem="EKr-6X-weJ" secondAttribute="leading" id="taB-4o-BQf"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstItem="YcY-tZ-Ga6" firstAttribute="width" secondItem="qfH-9X-kBZ" secondAttribute="width" id="5XJ-Oq-N4o"/>
</constraints>
</stackView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" text="If they don't match, the security of your communication may be compromised." lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wT1-a7-XOh">
<rect key="frame" x="20" y="294.5" width="374" height="33.5"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" alignment="center" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="mVH-0o-ZrL">
<rect key="frame" x="20" y="358" width="374" height="44"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6wi-YQ-QmI" customClass="RoundedButton" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="177" height="44"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<inset key="contentEdgeInsets" minX="10" minY="0.0" maxX="10" maxY="0.0"/>
<state key="normal" title="Cancel">
<color key="titleColor" red="1" green="0.29411764709999999" blue="0.33333333329999998" alpha="1" colorSpace="calibratedRGB"/>
</state>
<connections>
<action selector="cancelButtonAction:" destination="V8j-Lb-PgC" eventType="touchUpInside" id="ytK-85-toE"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="3pY-eX-Qfn" customClass="RoundedButton" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="197" y="0.0" width="177" height="44"/>
<inset key="contentEdgeInsets" minX="10" minY="0.0" maxX="10" maxY="0.0"/>
<state key="normal" title="Verify">
<color key="titleColor" red="0.01176470588" green="0.70196078429999997" blue="0.50588235290000005" alpha="1" colorSpace="calibratedRGB"/>
</state>
<connections>
<action selector="verifyButtonAction:" destination="V8j-Lb-PgC" eventType="touchUpInside" id="cfQ-bJ-jrr"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstAttribute="height" priority="750" constant="44" id="BCf-fL-ZMJ"/>
<constraint firstItem="3pY-eX-Qfn" firstAttribute="height" secondItem="mVH-0o-ZrL" secondAttribute="height" priority="999" id="WUy-05-S5d"/>
<constraint firstItem="6wi-YQ-QmI" firstAttribute="height" secondItem="mVH-0o-ZrL" secondAttribute="height" priority="999" id="mZw-S9-WUz"/>
</constraints>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="mVH-0o-ZrL" firstAttribute="leading" secondItem="voD-3Q-ryt" secondAttribute="leading" constant="20" id="1x2-p1-gBl"/>
<constraint firstAttribute="bottom" secondItem="mVH-0o-ZrL" secondAttribute="bottom" constant="100" id="3Ks-I4-3Pa"/>
<constraint firstItem="qfH-9X-kBZ" firstAttribute="top" secondItem="RIj-L9-tZn" secondAttribute="bottom" constant="20" id="7wU-kb-txG"/>
<constraint firstItem="wT1-a7-XOh" firstAttribute="trailing" secondItem="qfH-9X-kBZ" secondAttribute="trailing" id="9ws-hQ-6ag"/>
<constraint firstItem="RIj-L9-tZn" firstAttribute="leading" secondItem="voD-3Q-ryt" secondAttribute="leading" constant="20" id="B24-EF-h5n"/>
<constraint firstItem="RIj-L9-tZn" firstAttribute="top" secondItem="voD-3Q-ryt" secondAttribute="top" constant="20" id="BMO-Kj-hUI"/>
<constraint firstItem="qfH-9X-kBZ" firstAttribute="trailing" secondItem="RIj-L9-tZn" secondAttribute="trailing" id="f5i-AM-Rae"/>
<constraint firstAttribute="width" priority="750" constant="500" id="glD-Sz-73O"/>
<constraint firstAttribute="trailing" secondItem="mVH-0o-ZrL" secondAttribute="trailing" constant="20" id="oL7-Le-sqy"/>
<constraint firstItem="mVH-0o-ZrL" firstAttribute="top" secondItem="wT1-a7-XOh" secondAttribute="bottom" constant="30" id="rxl-Le-eol"/>
<constraint firstItem="qfH-9X-kBZ" firstAttribute="leading" secondItem="RIj-L9-tZn" secondAttribute="leading" id="sNm-19-5lu"/>
<constraint firstAttribute="trailing" secondItem="RIj-L9-tZn" secondAttribute="trailing" constant="20" id="ucH-Ci-kvn"/>
<constraint firstItem="wT1-a7-XOh" firstAttribute="leading" secondItem="qfH-9X-kBZ" secondAttribute="leading" id="w6D-nQ-QPq"/>
<constraint firstItem="wT1-a7-XOh" firstAttribute="top" secondItem="qfH-9X-kBZ" secondAttribute="bottom" constant="20" id="zv7-lG-ks8"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="voD-3Q-ryt" secondAttribute="bottom" id="63a-5e-ptU"/>
<constraint firstItem="voD-3Q-ryt" firstAttribute="centerX" secondItem="e7g-um-WO4" secondAttribute="centerX" id="P2G-mq-gQW"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="voD-3Q-ryt" secondAttribute="trailing" id="QgV-SO-5yf"/>
<constraint firstItem="voD-3Q-ryt" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="e7g-um-WO4" secondAttribute="leading" id="YPo-u1-PtT"/>
<constraint firstItem="voD-3Q-ryt" firstAttribute="top" secondItem="e7g-um-WO4" secondAttribute="top" id="rhQ-96-szL"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="e7g-um-WO4" secondAttribute="trailing" id="GyG-Fh-PME"/>
<constraint firstItem="e7g-um-WO4" firstAttribute="width" secondItem="9U2-KL-ZVA" secondAttribute="width" id="Ok2-WQ-Zgc"/>
<constraint firstAttribute="bottom" secondItem="e7g-um-WO4" secondAttribute="bottom" id="Y46-NP-zAc"/>
<constraint firstItem="e7g-um-WO4" firstAttribute="leading" secondItem="9U2-KL-ZVA" secondAttribute="leading" id="aoV-Yh-AcD"/>
<constraint firstItem="e7g-um-WO4" firstAttribute="top" secondItem="9U2-KL-ZVA" secondAttribute="top" id="pFN-bA-SHw"/>
</constraints>
</scrollView>
</subviews>
<color key="backgroundColor" red="0.94509803921568625" green="0.96078431372549022" blue="0.97254901960784312" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="9U2-KL-ZVA" secondAttribute="bottom" id="7Cb-nY-CsO"/>
<constraint firstItem="9U2-KL-ZVA" firstAttribute="leading" secondItem="bFg-jh-JZB" secondAttribute="leading" id="GdQ-hK-muG"/>
<constraint firstItem="bFg-jh-JZB" firstAttribute="trailing" secondItem="9U2-KL-ZVA" secondAttribute="trailing" id="sbD-ek-vGJ"/>
<constraint firstItem="bFg-jh-JZB" firstAttribute="top" secondItem="9U2-KL-ZVA" secondAttribute="top" id="wTB-V6-IHV"/>
</constraints>
<viewLayoutGuide key="safeArea" id="bFg-jh-JZB"/>
</view>
<connections>
<outlet property="additionalInformationLabel" destination="wT1-a7-XOh" id="5a3-Q0-gKF"/>
<outlet property="cancelButton" destination="6wi-YQ-QmI" id="0t1-M8-B6e"/>
<outlet property="deviceIdLabel" destination="WHf-qc-H4w" id="jmP-9Y-cXH"/>
<outlet property="deviceIdTitleLabel" destination="uVC-qK-ET7" id="ObX-Ys-hcO"/>
<outlet property="deviceKeyLabel" destination="5fG-Wi-cVH" id="a71-J8-TuA"/>
<outlet property="deviceKeyTitleLabel" destination="tBF-i0-Q4C" id="hBk-B1-Htu"/>
<outlet property="deviceNameLabel" destination="9SQ-lH-Hur" id="jqo-Y2-JzC"/>
<outlet property="deviceNameTitleLabel" destination="tp3-dZ-JyO" id="4Mt-qK-wfm"/>
<outlet property="informationLabel" destination="RIj-L9-tZn" id="TlB-EU-XGq"/>
<outlet property="scrollView" destination="9U2-KL-ZVA" id="ojG-2y-X7b"/>
<outlet property="verifyButton" destination="3pY-eX-Qfn" id="qhX-1D-gp9"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="zK0-v6-7Wt" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-3198.5507246376815" y="-647.54464285714278"/>
</scene>
</scenes>
</document>

View file

@ -0,0 +1,224 @@
// File created from ScreenTemplate
// $ createScreen.sh KeyVerification/Device/ManuallyVerify KeyVerificationManuallyVerify
/*
Copyright 2020 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import UIKit
final class KeyVerificationManuallyVerifyViewController: UIViewController {
// MARK: - Constants
// MARK: - Properties
// MARK: Outlets
@IBOutlet private weak var scrollView: UIScrollView!
@IBOutlet private weak var informationLabel: UILabel!
@IBOutlet private weak var deviceNameTitleLabel: UILabel!
@IBOutlet private weak var deviceNameLabel: UILabel!
@IBOutlet private weak var deviceIdTitleLabel: UILabel!
@IBOutlet private weak var deviceIdLabel: UILabel!
@IBOutlet private weak var deviceKeyTitleLabel: UILabel!
@IBOutlet private weak var deviceKeyLabel: UILabel!
@IBOutlet private weak var additionalInformationLabel: UILabel!
@IBOutlet private weak var verifyButton: RoundedButton!
@IBOutlet private weak var cancelButton: RoundedButton!
// MARK: Private
private var viewModel: KeyVerificationManuallyVerifyViewModelType!
private var theme: Theme!
private var errorPresenter: MXKErrorPresentation!
private var activityPresenter: ActivityIndicatorPresenter!
// MARK: - Setup
class func instantiate(with viewModel: KeyVerificationManuallyVerifyViewModelType) -> KeyVerificationManuallyVerifyViewController {
let viewController = StoryboardScene.KeyVerificationManuallyVerifyViewController.initialScene.instantiate()
viewController.viewModel = viewModel
viewController.theme = ThemeService.shared().theme
return viewController
}
// MARK: - Life cycle
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.setupViews()
self.activityPresenter = ActivityIndicatorPresenter()
self.errorPresenter = MXKErrorAlertPresentation()
self.registerThemeServiceDidChangeThemeNotification()
self.update(theme: self.theme)
self.viewModel.viewDelegate = self
self.viewModel.process(viewAction: .loadData)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let navigationController = self.navigationController {
if navigationController.navigationBar.isHidden == true {
self.navigationItem.hidesBackButton = true
// Show navigation bar if needed
navigationController.setNavigationBarHidden(false, animated: animated)
} else {
// Hide back button
self.navigationItem.setHidesBackButton(true, animated: animated)
}
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Fix label height after orientation change. See here https://www.objc.io/issues/3-views/advanced-auto-layout-toolbox/#intrinsic-content-size-of-multi-line-text for more information.
self.informationLabel.vc_fixMultilineHeight()
self.deviceNameTitleLabel.vc_fixMultilineHeight()
self.deviceNameLabel.vc_fixMultilineHeight()
self.deviceIdLabel.vc_fixMultilineHeight()
self.deviceIdTitleLabel.vc_fixMultilineHeight()
self.deviceKeyTitleLabel.vc_fixMultilineHeight()
self.deviceKeyLabel.vc_fixMultilineHeight()
self.additionalInformationLabel.vc_fixMultilineHeight()
self.view.layoutIfNeeded()
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return self.theme.statusBarStyle
}
// MARK: - Private
private func update(theme: Theme) {
self.theme = theme
self.view.backgroundColor = theme.headerBackgroundColor
if let navigationBar = self.navigationController?.navigationBar {
theme.applyStyle(onNavigationBar: navigationBar)
}
self.informationLabel.textColor = theme.textPrimaryColor
self.deviceNameTitleLabel.textColor = theme.textPrimaryColor
self.deviceNameLabel.textColor = theme.textPrimaryColor
self.deviceIdTitleLabel.textColor = theme.textPrimaryColor
self.deviceIdLabel.textColor = theme.textPrimaryColor
self.deviceKeyTitleLabel.textColor = theme.textPrimaryColor
self.deviceKeyLabel.textColor = theme.textPrimaryColor
self.additionalInformationLabel.textColor = theme.textPrimaryColor
self.cancelButton.update(theme: theme)
self.verifyButton.update(theme: theme)
}
private func registerThemeServiceDidChangeThemeNotification() {
NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil)
}
@objc private func themeDidChange() {
self.update(theme: ThemeService.shared().theme)
}
private func setupViews() {
let cancelBarButtonItem = MXKBarButtonItem(title: VectorL10n.cancel, style: .plain) { [weak self] in
self?.cancelAction()
}
self.navigationItem.rightBarButtonItem = cancelBarButtonItem
self.title = VectorL10n.keyVerificationManuallyVerifyDeviceTitle
self.informationLabel.text = VectorL10n.keyVerificationManuallyVerifyDeviceInstruction
self.deviceNameTitleLabel.text = VectorL10n.keyVerificationManuallyVerifyDeviceNameTitle
self.deviceIdTitleLabel.text = VectorL10n.keyVerificationManuallyVerifyDeviceIdTitle
self.deviceKeyTitleLabel.text = VectorL10n.keyVerificationManuallyVerifyDeviceKeyTitle
self.additionalInformationLabel.text = VectorL10n.keyVerificationManuallyVerifyDeviceAdditionalInformation
self.deviceNameLabel.text = nil
self.deviceIdLabel.text = nil
self.deviceKeyLabel.text = nil
self.cancelButton.actionStyle = .cancel
}
private func render(viewState: KeyVerificationManuallyVerifyViewState) {
switch viewState {
case .loading:
self.renderLoading()
case .loaded(let viewData):
self.renderLoaded(viewData: viewData)
case .error(let error):
self.render(error: error)
}
}
private func renderLoading() {
self.activityPresenter.presentActivityIndicator(on: self.view, animated: true)
}
private func renderLoaded(viewData: KeyVerificationManuallyVerifyViewData) {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
self.deviceNameLabel.text = viewData.deviceName
self.deviceIdLabel.text = viewData.deviceId
self.deviceKeyLabel.text = viewData.deviceKey
}
private func render(error: Error) {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: nil)
}
// MARK: - Actions
@IBAction private func verifyButtonAction(_ sender: Any) {
self.viewModel.process(viewAction: .verify)
}
@IBAction private func cancelButtonAction(_ sender: Any) {
self.cancelAction()
}
private func cancelAction() {
self.viewModel.process(viewAction: .cancel)
}
}
// MARK: - KeyVerificationManuallyVerifyViewModelViewDelegate
extension KeyVerificationManuallyVerifyViewController: KeyVerificationManuallyVerifyViewModelViewDelegate {
func keyVerificationManuallyVerifyViewModel(_ viewModel: KeyVerificationManuallyVerifyViewModelType, didUpdateViewState viewSate: KeyVerificationManuallyVerifyViewState) {
self.render(viewState: viewSate)
}
}

View file

@ -0,0 +1,113 @@
// File created from ScreenTemplate
// $ createScreen.sh KeyVerification/Device/ManuallyVerify KeyVerificationManuallyVerify
/*
Copyright 2020 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import Foundation
enum KeyVerificationManuallyVerifyViewModelError: Error {
case unknown
case deviceNotFound
}
final class KeyVerificationManuallyVerifyViewModel: KeyVerificationManuallyVerifyViewModelType {
// MARK: - Properties
// MARK: Private
private let session: MXSession
private let deviceId: String
private let userId: String
private var currentOperation: MXHTTPOperation?
// MARK: Public
weak var viewDelegate: KeyVerificationManuallyVerifyViewModelViewDelegate?
weak var coordinatorDelegate: KeyVerificationManuallyVerifyViewModelCoordinatorDelegate?
// MARK: - Setup
init(session: MXSession, deviceId: String, userId: String) {
self.session = session
self.deviceId = deviceId
self.userId = userId
}
deinit {
self.cancelOperations()
}
// MARK: - Public
func process(viewAction: KeyVerificationManuallyVerifyViewAction) {
switch viewAction {
case .loadData:
self.loadData()
case .verify:
self.verifyDevice()
case .cancel:
self.cancelOperations()
self.coordinatorDelegate?.keyVerificationManuallyVerifyViewModelDidCancel(self)
}
}
// MARK: - Private
private func loadData() {
guard let deviceInfo = self.session.crypto.device(withDeviceId: self.deviceId, ofUser: self.userId) else {
self.update(viewState: .error(KeyVerificationManuallyVerifyViewModelError.deviceNotFound))
return
}
var deviceKey: String?
if let deviceFingerprint = deviceInfo.fingerprint {
deviceKey = MXTools.addWhiteSpaces(to: deviceFingerprint, every: 4)
}
let viewData = KeyVerificationManuallyVerifyViewData(deviceId: self.deviceId, deviceName: deviceInfo.displayName, deviceKey: deviceKey)
self.update(viewState: .loaded(viewData))
}
private func update(viewState: KeyVerificationManuallyVerifyViewState) {
self.viewDelegate?.keyVerificationManuallyVerifyViewModel(self, didUpdateViewState: viewState)
}
private func verifyDevice() {
self.update(viewState: .loading)
self.session.crypto.setDeviceVerification(.verified, forDevice: self.deviceId, ofUser: self.userId, success: { [weak self] in
guard let self = self else {
return
}
self.coordinatorDelegate?.keyVerificationManuallyVerifyViewModel(self, didVerifiedDeviceWithId: self.deviceId, of: self.userId)
}, failure: { [weak self] (error) in
guard let self = self else {
return
}
let finalError = error ?? KeyVerificationManuallyVerifyViewModelError.unknown
self.update(viewState: .error(finalError))
})
}
private func cancelOperations() {
self.currentOperation?.cancel()
}
}

View file

@ -0,0 +1,37 @@
// File created from ScreenTemplate
// $ createScreen.sh KeyVerification/Device/ManuallyVerify KeyVerificationManuallyVerify
/*
Copyright 2020 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import Foundation
protocol KeyVerificationManuallyVerifyViewModelViewDelegate: class {
func keyVerificationManuallyVerifyViewModel(_ viewModel: KeyVerificationManuallyVerifyViewModelType, didUpdateViewState viewSate: KeyVerificationManuallyVerifyViewState)
}
protocol KeyVerificationManuallyVerifyViewModelCoordinatorDelegate: class {
func keyVerificationManuallyVerifyViewModel(_ viewModel: KeyVerificationManuallyVerifyViewModelType, didVerifiedDeviceWithId deviceId: String, of userId: String)
func keyVerificationManuallyVerifyViewModelDidCancel(_ viewModel: KeyVerificationManuallyVerifyViewModelType)
}
/// Protocol describing the view model used by `KeyVerificationManuallyVerifyViewController`
protocol KeyVerificationManuallyVerifyViewModelType {
var viewDelegate: KeyVerificationManuallyVerifyViewModelViewDelegate? { get set }
var coordinatorDelegate: KeyVerificationManuallyVerifyViewModelCoordinatorDelegate? { get set }
func process(viewAction: KeyVerificationManuallyVerifyViewAction)
}

View file

@ -0,0 +1,32 @@
// File created from ScreenTemplate
// $ createScreen.sh KeyVerification/Device/ManuallyVerify KeyVerificationManuallyVerify
/*
Copyright 2020 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import Foundation
struct KeyVerificationManuallyVerifyViewData {
let deviceId: String
let deviceName: String?
let deviceKey: String?
}
/// KeyVerificationManuallyVerifyViewController view state
enum KeyVerificationManuallyVerifyViewState {
case loading
case loaded(_ viewData: KeyVerificationManuallyVerifyViewData)
case error(Error)
}

View file

@ -21,7 +21,7 @@
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="RcA-LK-bqZ">
<rect key="frame" x="0.0" y="254" width="375" height="179"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="For extra security, verify @user:matrix.org by checking a one-time code on both your devices." textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ii0-Vq-vuo">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="For extra security, verify @user:matrix.org by checking a one-time code on both your devices." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ii0-Vq-vuo">
<rect key="frame" x="20" y="10" width="335" height="36"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="textColor"/>

View file

@ -74,6 +74,21 @@ final class KeyVerificationSelfVerifyStartViewController: UIViewController {
self.viewModel.process(viewAction: .loadData)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let navigationController = self.navigationController {
if navigationController.navigationBar.isHidden == true {
self.navigationItem.hidesBackButton = true
// Show navigation bar if needed
navigationController.setNavigationBarHidden(false, animated: animated)
} else {
// Hide back button
self.navigationItem.setHidesBackButton(true, animated: animated)
}
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()

View file

@ -63,6 +63,23 @@ final class KeyVerificationSelfVerifyWaitViewModel: KeyVerificationSelfVerifyWai
// MARK: - Private
private func loadData() {
if !self.isNewSignIn {
print("[KeyVerificationSelfVerifyWaitViewModel] loadData: Send a verification request to all devices")
let keyVerificationService = KeyVerificationService()
self.verificationManager.requestVerificationByToDevice(withUserId: self.session.myUserId, deviceIds: nil, methods: keyVerificationService.supportedKeyVerificationMethods(), success: { [weak self] (keyVerificationRequest) in
guard let self = self else {
return
}
self.keyVerificationRequest = keyVerificationRequest
}, failure: { [weak self] error in
self?.update(viewState: .error(error))
})
}
self.registerKeyVerificationManagerNewRequestNotification(for: self.verificationManager)
self.update(viewState: .loaded(self.isNewSignIn))
self.registerTransactionDidStateChangeNotification()

View file

@ -65,6 +65,10 @@ final class UserVerificationSessionStatusCoordinator: UserVerificationSessionSta
// MARK: - UserVerificationSessionStatusViewModelCoordinatorDelegate
extension UserVerificationSessionStatusCoordinator: UserVerificationSessionStatusViewModelCoordinatorDelegate {
func userVerificationSessionStatusViewModel(_ viewModel: UserVerificationSessionStatusViewModelType, wantsToVerifyDeviceWithId deviceId: String, for userId: String) {
self.delegate?.userVerificationSessionStatusCoordinator(self, wantsToVerifyDeviceWithId: deviceId, for: userId)
}
func userVerificationSessionStatusViewModel(_ viewModel: UserVerificationSessionStatusViewModelType, wantsToManuallyVerifyDeviceWithId deviceId: String, for userId: String) {
self.delegate?.userVerificationSessionStatusCoordinator(self, wantsToManuallyVerifyDeviceWithId: deviceId, for: userId)
}

View file

@ -19,6 +19,7 @@
import Foundation
protocol UserVerificationSessionStatusCoordinatorDelegate: class {
func userVerificationSessionStatusCoordinator(_ coordinator: UserVerificationSessionStatusCoordinatorType, wantsToVerifyDeviceWithId deviceId: String, for userId: String)
func userVerificationSessionStatusCoordinator(_ coordinator: UserVerificationSessionStatusCoordinatorType, wantsToManuallyVerifyDeviceWithId deviceId: String, for userId: String)
func userVerificationSessionStatusCoordinatorDidClose(_ coordinator: UserVerificationSessionStatusCoordinatorType)
}

View file

@ -22,5 +22,6 @@ import Foundation
enum UserVerificationSessionStatusViewAction {
case loadData
case verify
case verifyManually
case close
}

View file

@ -22,7 +22,7 @@
<rect key="frame" x="0.0" y="20" width="375" height="647"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sX2-Xu-9f5">
<rect key="frame" x="0.0" y="0.0" width="375" height="296.5"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="348.5"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="1lx-d3-6c2">
<rect key="frame" x="0.0" y="0.0" width="375" height="108"/>
@ -102,10 +102,10 @@
</constraints>
</view>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="rB7-Ct-Mq7">
<rect key="frame" x="0.0" y="148.5" width="375" height="148"/>
<rect key="frame" x="0.0" y="148.5" width="375" height="200"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="oRN-W6-TVF">
<rect key="frame" x="0.0" y="0.0" width="375" height="148"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="200"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dd2-N5-GEx">
<rect key="frame" x="20" y="10" width="335" height="54"/>
@ -123,7 +123,7 @@
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="15"/>
<inset key="contentEdgeInsets" minX="30" minY="0.0" maxX="30" maxY="0.0"/>
<state key="normal" title="Manually verify">
<state key="normal" title="Verify">
<color key="titleColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
@ -131,15 +131,36 @@
<action selector="verifyButtonAction:" destination="edG-Ef-G5W" eventType="touchUpInside" id="gGx-OT-X5w"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="249" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="zpI-gc-wUh">
<rect key="frame" x="76" y="136" width="223" height="44"/>
<accessibility key="accessibilityConfiguration" identifier="AuthenticationVCLoginButton"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="100" id="e0g-or-1Fr"/>
<constraint firstAttribute="height" constant="44" id="m7k-72-n0t"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="15"/>
<inset key="contentEdgeInsets" minX="30" minY="0.0" maxX="30" maxY="0.0"/>
<state key="normal" title="Manually Verify by Text">
<color key="titleColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="manuallyVerifyButtonAction:" destination="edG-Ef-G5W" eventType="touchUpInside" id="fpP-Yv-6dD"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="HiI-uV-Hjw" secondAttribute="bottom" constant="20" id="3bP-Hs-m42"/>
<constraint firstItem="zpI-gc-wUh" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="oRN-W6-TVF" secondAttribute="leading" constant="20" id="3AK-6W-oYS"/>
<constraint firstAttribute="trailing" secondItem="dd2-N5-GEx" secondAttribute="trailing" constant="20" id="BHw-Yv-ceG"/>
<constraint firstItem="dd2-N5-GEx" firstAttribute="leading" secondItem="oRN-W6-TVF" secondAttribute="leading" constant="20" id="BV7-Vu-PQR"/>
<constraint firstItem="HiI-uV-Hjw" firstAttribute="top" secondItem="dd2-N5-GEx" secondAttribute="bottom" constant="20" id="BtT-Mg-Okq"/>
<constraint firstItem="HiI-uV-Hjw" firstAttribute="centerX" secondItem="oRN-W6-TVF" secondAttribute="centerX" id="Ign-Yp-tpB"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="zpI-gc-wUh" secondAttribute="trailing" constant="20" id="T1v-Iv-kls"/>
<constraint firstItem="dd2-N5-GEx" firstAttribute="top" secondItem="oRN-W6-TVF" secondAttribute="top" constant="10" id="Ygn-tl-ahK"/>
<constraint firstAttribute="bottom" secondItem="zpI-gc-wUh" secondAttribute="bottom" constant="20" id="bsQ-04-17O"/>
<constraint firstItem="zpI-gc-wUh" firstAttribute="top" secondItem="HiI-uV-Hjw" secondAttribute="bottom" constant="8" symbolic="YES" id="i06-nz-c3n"/>
<constraint firstItem="zpI-gc-wUh" firstAttribute="centerX" secondItem="oRN-W6-TVF" secondAttribute="centerX" id="lCz-Rb-vQB"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="HiI-uV-Hjw" secondAttribute="trailing" constant="20" id="nqA-lS-ubx"/>
<constraint firstItem="HiI-uV-Hjw" firstAttribute="width" secondItem="oRN-W6-TVF" secondAttribute="width" priority="250" id="qp1-z5-eP9"/>
<constraint firstItem="HiI-uV-Hjw" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="oRN-W6-TVF" secondAttribute="leading" constant="20" id="uNl-Ok-uee"/>
@ -191,6 +212,7 @@
<outlet property="deviceInformationLabel" destination="FET-ZT-Q69" id="D8n-5b-H4p"/>
<outlet property="deviceStatusImageView" destination="0ME-4K-MWA" id="kgp-dT-Q0P"/>
<outlet property="informationLabel" destination="CTY-XM-iLf" id="qVC-lS-YOY"/>
<outlet property="manuallyVerifyButton" destination="zpI-gc-wUh" id="tt1-h1-TrK"/>
<outlet property="titleLabel" destination="mXI-Sg-wYe" id="Wrj-QM-srt"/>
<outlet property="untrustedSessionContainerView" destination="oRN-W6-TVF" id="9sc-53-MWY"/>
<outlet property="untrustedSessionInformationLabel" destination="dd2-N5-GEx" id="6TB-Ve-OyC"/>

View file

@ -45,6 +45,7 @@ final class UserVerificationSessionStatusViewController: UIViewController {
@IBOutlet private weak var untrustedSessionContainerView: UIView!
@IBOutlet private weak var untrustedSessionInformationLabel: UILabel!
@IBOutlet private weak var verifyButton: UIButton!
@IBOutlet private weak var manuallyVerifyButton: UIButton!
// MARK: Private
@ -111,6 +112,8 @@ final class UserVerificationSessionStatusViewController: UIViewController {
self.untrustedSessionInformationLabel.textColor = theme.textPrimaryColor
self.verifyButton.vc_setBackgroundColor(theme.tintColor, for: .normal)
theme.applyStyle(onButton: self.manuallyVerifyButton)
}
private func registerThemeServiceDidChangeThemeNotification() {
@ -124,6 +127,8 @@ final class UserVerificationSessionStatusViewController: UIViewController {
private func setupViews() {
self.closeButton.layer.masksToBounds = true
self.verifyButton.layer.masksToBounds = true
self.manuallyVerifyButton.setTitle(VectorL10n.userVerificationSessionDetailsVerifyActionCurrentUserManually, for: .normal)
}
private func render(viewState: UserVerificationSessionStatusViewState) {
@ -149,6 +154,8 @@ final class UserVerificationSessionStatusViewController: UIViewController {
self.untrustedSessionContainerView.isHidden = viewData.isDeviceTrusted
self.manuallyVerifyButton.isHidden = !viewData.isCurrentUser
if viewData.isDeviceTrusted {
badgeImage = Asset.Images.encryptionTrusted.image
title = VectorL10n.userVerificationSessionDetailsTrustedTitle
@ -181,7 +188,12 @@ final class UserVerificationSessionStatusViewController: UIViewController {
private func render(error: Error) {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: nil)
self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: {
if case UserVerificationSessionStatusViewModelError.deviceNotFound = error {
self.viewModel.process(viewAction: .close)
}
})
}
private func buildUserInfoText(with userId: String, userDisplayName: String?) -> String {
@ -258,6 +270,10 @@ final class UserVerificationSessionStatusViewController: UIViewController {
@IBAction private func verifyButtonAction(_ sender: Any) {
self.viewModel.process(viewAction: .verify)
}
@IBAction private func manuallyVerifyButtonAction(_ sender: Any) {
self.viewModel.process(viewAction: .verifyManually)
}
}

View file

@ -64,6 +64,8 @@ final class UserVerificationSessionStatusViewModel: UserVerificationSessionStatu
case .loadData:
self.loadData()
case .verify:
self.coordinatorDelegate?.userVerificationSessionStatusViewModel(self, wantsToVerifyDeviceWithId: self.deviceId, for: self.userId)
case .verifyManually:
self.coordinatorDelegate?.userVerificationSessionStatusViewModel(self, wantsToManuallyVerifyDeviceWithId: self.deviceId, for: self.userId)
case .close:
self.coordinatorDelegate?.userVerificationSessionStatusViewModelDidClose(self)

View file

@ -23,6 +23,7 @@ protocol UserVerificationSessionStatusViewModelViewDelegate: class {
}
protocol UserVerificationSessionStatusViewModelCoordinatorDelegate: class {
func userVerificationSessionStatusViewModel(_ viewModel: UserVerificationSessionStatusViewModelType, wantsToVerifyDeviceWithId deviceId: String, for userId: String)
func userVerificationSessionStatusViewModel(_ viewModel: UserVerificationSessionStatusViewModelType, wantsToManuallyVerifyDeviceWithId deviceId: String, for userId: String)
func userVerificationSessionStatusViewModelDidClose(_ viewModel: UserVerificationSessionStatusViewModelType)
}

View file

@ -140,6 +140,16 @@ final class UserVerificationCoordinator: NSObject, UserVerificationCoordinatorTy
self.presenter.toPresentable().present(alert, animated: true, completion: nil)
}
private func presentManualDeviceVerification(for deviceId: String, of userId: String) {
let coordinator = KeyVerificationManuallyVerifyCoordinator(session: self.session, deviceId: deviceId, userId: userId)
coordinator.delegate = self
coordinator.start()
self.navigationRouter.push(coordinator, animated: true) {
self.remove(childCoordinator: coordinator)
}
}
}
// MARK: - UserVerificationSessionsStatusCoordinatorDelegate
@ -159,11 +169,14 @@ extension UserVerificationCoordinator: UserVerificationSessionsStatusCoordinator
// MARK: - UserVerificationSessionStatusCoordinatorDelegate
extension UserVerificationCoordinator: UserVerificationSessionStatusCoordinatorDelegate {
func userVerificationSessionStatusCoordinator(_ coordinator: UserVerificationSessionStatusCoordinatorType, wantsToManuallyVerifyDeviceWithId deviceId: String, for userId: String) {
func userVerificationSessionStatusCoordinator(_ coordinator: UserVerificationSessionStatusCoordinatorType, wantsToVerifyDeviceWithId deviceId: String, for userId: String) {
self.presentDeviceVerification(for: deviceId)
}
func userVerificationSessionStatusCoordinator(_ coordinator: UserVerificationSessionStatusCoordinatorType, wantsToManuallyVerifyDeviceWithId deviceId: String, for userId: String) {
self.presentManualDeviceVerification(for: deviceId, of: userId)
}
func userVerificationSessionStatusCoordinatorDidClose(_ coordinator: UserVerificationSessionStatusCoordinatorType) {
self.presenter.toPresentable().dismiss(animated: true) {
@ -189,3 +202,19 @@ extension UserVerificationCoordinator: KeyVerificationCoordinatorDelegate {
}
}
}
// MARK: - KeyVerificationManuallyVerifyCoordinatorDelegate
extension UserVerificationCoordinator: KeyVerificationManuallyVerifyCoordinatorDelegate {
func keyVerificationManuallyVerifyCoordinator(_ coordinator: KeyVerificationManuallyVerifyCoordinatorType, didVerifiedDeviceWithId deviceId: String, of userId: String) {
self.presenter.toPresentable().dismiss(animated: true) {
self.remove(childCoordinator: coordinator)
}
}
func keyVerificationManuallyVerifyCoordinatorDidCancel(_ coordinator: KeyVerificationManuallyVerifyCoordinatorType) {
self.presenter.toPresentable().dismiss(animated: true) {
self.remove(childCoordinator: coordinator)
}
}
}

View file

@ -468,9 +468,16 @@
return;
}
[self.mxRoom encryptionTrustLevelForUserId:userId onComplete:^(UserEncryptionTrustLevel userEncryptionTrustLevel) {
self.encryptionTrustLevel = userEncryptionTrustLevel;
[self updateMemberInfo];
[self.mxRoom.mxSession.crypto downloadKeys:@[userId] forceDownload:YES success:^(MXUsersDevicesMap<MXDeviceInfo *> *usersDevicesInfoMap, NSDictionary<NSString *,MXCrossSigningInfo *> *crossSigningKeysMap) {
[self.mxRoom encryptionTrustLevelForUserId:userId onComplete:^(UserEncryptionTrustLevel userEncryptionTrustLevel) {
self.encryptionTrustLevel = userEncryptionTrustLevel;
[self updateMemberInfo];
}];
} failure:^(NSError *error) {
[self.mxRoom encryptionTrustLevelForUserId:userId onComplete:^(UserEncryptionTrustLevel userEncryptionTrustLevel) {
self.encryptionTrustLevel = userEncryptionTrustLevel;
[self updateMemberInfo];
}];
}];
}

View file

@ -20,5 +20,7 @@
@interface SettingsViewController : MXKTableViewController<UITextFieldDelegate, MXKCountryPickerViewControllerDelegate, MXKLanguagePickerViewControllerDelegate, MXKDataSourceDelegate>
+ (instancetype)instantiate;
@end

View file

@ -261,6 +261,13 @@ SettingsIdentityServerCoordinatorBridgePresenterDelegate>
@implementation SettingsViewController
+ (instancetype)instantiate
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
SettingsViewController *settingsViewController = [storyboard instantiateViewControllerWithIdentifier:@"SettingsViewController"];
return settingsViewController;
}
- (void)finalizeInit
{
[super finalizeInit];

View file

@ -27,6 +27,9 @@
#import "MXRoom+Riot.h"
#import "MXSession+Riot.h"
#import "SettingsViewController.h"
#import "SecurityViewController.h"
#import "Riot-Swift.h"
@interface MasterTabBarController ()
@ -66,7 +69,7 @@
@property(nonatomic,getter=isHidden) BOOL hidden;
@property(nonatomic) BOOL verifyCurrentSessionAlertHasBeenDisplayed;
@property(nonatomic) BOOL reviewSessionAlertHasBeenDisplayed;
@end
@ -77,6 +80,9 @@
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Note: UITabBarViewController shoud not be embed in a UINavigationController (https://github.com/vector-im/riot-ios/issues/3086)
[self vc_removeBackTitle];
// Retrieve the all view controllers
_homeViewController = self.viewControllers[TABBAR_HOME_INDEX];
_favouritesViewController = self.viewControllers[TABBAR_FAVOURITES_INDEX];
@ -209,7 +215,7 @@
[childViewControllers removeAllObjects];
}
[self presentVerifyCurrentSessionAlertIfNeeded];
[self presentReviewSessionsAlertIfNeeded];
}
if (unifiedSearchViewController)
@ -219,55 +225,6 @@
}
}
- (void)presentVerifyCurrentSessionAlertIfNeeded
{
if (RiotSettings.shared.hideVerifyThisSessionAlert || self.verifyCurrentSessionAlertHasBeenDisplayed)
{
return;
}
MXSession *mainSession = self.mxSessions.firstObject;
if (self.viewLoaded
&& mainSession.state >= MXSessionStateStoreDataReady
&& mainSession.crypto.crossSigning
&& mainSession.crypto.crossSigning.state == MXCrossSigningStateCrossSigningExists)
{
self.verifyCurrentSessionAlertHasBeenDisplayed = YES;
[self presentVerifyCurrentSessionAlertWithSession:mainSession];
}
}
- (void)presentVerifyCurrentSessionAlertWithSession:(MXSession*)session
{
[currentAlert dismissViewControllerAnimated:NO completion:nil];
UIAlertController *alert = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"key_verification_self_verify_current_session_alert_title", @"Vector", nil)
message:NSLocalizedStringFromTable(@"key_verification_self_verify_current_session_alert_message", @"Vector", nil)
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"key_verification_self_verify_current_session_alert_validate_action", @"Vector", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
[[AppDelegate theDelegate] presentCompleteSecurityForSession:session];
}]];
[alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"later", @"Vector", nil)
style:UIAlertActionStyleCancel
handler:nil]];
[alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"do_not_ask_again", @"Vector", nil)
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction * action) {
RiotSettings.shared.hideVerifyThisSessionAlert = YES;
}]];
[self presentViewController:alert animated:YES completion:nil];
currentAlert = alert;
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
@ -444,7 +401,7 @@
{
[self refreshTabBarBadges];
[self presentVerifyCurrentSessionAlertIfNeeded];
[self presentReviewSessionsAlertIfNeeded];
}
- (void)showAuthenticationScreen
@ -456,6 +413,8 @@
{
isAuthViewControllerPreparing = YES;
[self resetReviewSessionsFlags];
[[AppDelegate theDelegate] restoreInitialDisplay:^{
[self performSegueWithIdentifier:@"showAuth" sender:self];
@ -1034,6 +993,147 @@
[self presentViewController:currentAlert animated:YES completion:nil];
}
#pragma mark - Review session
- (void)presentReviewSessionsAlertIfNeeded
{
MXSession *mainSession = self.mxSessions.firstObject;
if (!(self.viewLoaded
&& mainSession.state >= MXSessionStateStoreDataReady
&& mainSession.crypto.crossSigning))
{
return;
}
switch (mainSession.crypto.crossSigning.state) {
case MXCrossSigningStateCrossSigningExists:
[self presentVerifyCurrentSessionAlertIfNeededWithSession:mainSession];
break;
case MXCrossSigningStateCanCrossSign:
[self presentReviewUnverifiedSessionsAlertIfNeededWithSession:mainSession];
break;
default:
break;
}
}
- (void)presentVerifyCurrentSessionAlertIfNeededWithSession:(MXSession*)session
{
if (RiotSettings.shared.hideVerifyThisSessionAlert || self.reviewSessionAlertHasBeenDisplayed)
{
return;
}
self.reviewSessionAlertHasBeenDisplayed = YES;
[self presentVerifyCurrentSessionAlertWithSession:session];
}
- (void)presentVerifyCurrentSessionAlertWithSession:(MXSession*)session
{
[currentAlert dismissViewControllerAnimated:NO completion:nil];
UIAlertController *alert = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"key_verification_self_verify_current_session_alert_title", @"Vector", nil)
message:NSLocalizedStringFromTable(@"key_verification_self_verify_current_session_alert_message", @"Vector", nil)
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"key_verification_self_verify_current_session_alert_validate_action", @"Vector", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
[[AppDelegate theDelegate] presentCompleteSecurityForSession:session];
}]];
[alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"later", @"Vector", nil)
style:UIAlertActionStyleCancel
handler:nil]];
[alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"do_not_ask_again", @"Vector", nil)
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction * action) {
RiotSettings.shared.hideVerifyThisSessionAlert = YES;
}]];
[self presentViewController:alert animated:YES completion:nil];
currentAlert = alert;
}
- (void)presentReviewUnverifiedSessionsAlertIfNeededWithSession:(MXSession*)session
{
if (RiotSettings.shared.hideReviewSessionsAlert || self.reviewSessionAlertHasBeenDisplayed)
{
return;
}
NSArray<MXDeviceInfo*> *devices = [session.crypto.store devicesForUser:session.myUserId].allValues;
BOOL isUserHasOneUnverifiedDevice = NO;
for (MXDeviceInfo *device in devices)
{
if (device.trustLevel.localVerificationStatus == MXDeviceUnknown)
{
isUserHasOneUnverifiedDevice = YES;
break;
}
}
if (isUserHasOneUnverifiedDevice)
{
self.reviewSessionAlertHasBeenDisplayed = YES;
[self presentReviewUnverifiedSessionsAlertWithSession:session];
}
}
- (void)presentReviewUnverifiedSessionsAlertWithSession:(MXSession*)session
{
[currentAlert dismissViewControllerAnimated:NO completion:nil];
UIAlertController *alert = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"key_verification_self_verify_unverified_sessions_alert_title", @"Vector", nil)
message:NSLocalizedStringFromTable(@"key_verification_self_verify_unverified_sessions_alert_message", @"Vector", nil)
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"key_verification_self_verify_unverified_sessions_alert_validate_action", @"Vector", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
[self showSettingsSecurityScreenForSession:session];
}]];
[alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"later", @"Vector", nil)
style:UIAlertActionStyleCancel
handler:nil]];
[alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"do_not_ask_again", @"Vector", nil)
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction * action) {
RiotSettings.shared.hideReviewSessionsAlert = YES;
}]];
[self presentViewController:alert animated:YES completion:nil];
currentAlert = alert;
}
- (void)showSettingsSecurityScreenForSession:(MXSession*)session
{
SettingsViewController *settingsViewController = [SettingsViewController instantiate];
[settingsViewController loadViewIfNeeded];
SecurityViewController *securityViewController = [SecurityViewController instantiateWithMatrixSession:session];
[[AppDelegate theDelegate] restoreInitialDisplay:^{
self.navigationController.viewControllers = @[self, settingsViewController, securityViewController];
}];
}
- (void)resetReviewSessionsFlags
{
self.reviewSessionAlertHasBeenDisplayed = NO;
RiotSettings.shared.hideVerifyThisSessionAlert = NO;
RiotSettings.shared.hideReviewSessionsAlert = NO;
}
#pragma mark - UITabBarDelegate
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item

View file

@ -17,11 +17,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.11.2</string>
<string>0.11.3</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>0.11.2</string>
<string>0.11.3</string>
<key>ITSAppUsesNonExemptEncryption</key>
<true/>
<key>ITSEncryptionExportComplianceCode</key>

View file

@ -17,9 +17,9 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>0.11.2</string>
<string>0.11.3</string>
<key>CFBundleVersion</key>
<string>0.11.2</string>
<string>0.11.3</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>

View file

@ -17,9 +17,9 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>0.11.2</string>
<string>0.11.3</string>
<key>CFBundleVersion</key>
<string>0.11.2</string>
<string>0.11.3</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>

View file

@ -68,7 +68,7 @@ final class FlowTemplateCoordinator: FlowTemplateCoordinatorType {
// MARK: - TemplateScreenCoordinatorDelegate
extension FlowTemplateCoordinator: TemplateScreenCoordinatorDelegate {
func templateScreenCoordinator(_ coordinator: TemplateScreenCoordinatorType, didCompleteWithMessage message: String) {
func templateScreenCoordinator(_ coordinator: TemplateScreenCoordinatorType, didCompleteWithUserDisplayName userDisplayName: String?) {
self.delegate?.flowTemplateCoordinatorDidComplete(self)
}

View file

@ -59,8 +59,8 @@ final class TemplateScreenCoordinator: TemplateScreenCoordinatorType {
// MARK: - TemplateScreenViewModelCoordinatorDelegate
extension TemplateScreenCoordinator: TemplateScreenViewModelCoordinatorDelegate {
func templateScreenViewModel(_ viewModel: TemplateScreenViewModelType, didCompleteWithMessage message: String) {
self.delegate?.templateScreenCoordinator(self, didCompleteWithMessage: message)
func templateScreenViewModel(_ viewModel: TemplateScreenViewModelType, didCompleteWithUserDisplayName userDisplayName: String?) {
self.delegate?.templateScreenCoordinator(self, didCompleteWithUserDisplayName: userDisplayName)
}
func templateScreenViewModelDidCancel(_ viewModel: TemplateScreenViewModelType) {

View file

@ -17,7 +17,7 @@
import Foundation
protocol TemplateScreenCoordinatorDelegate: class {
func templateScreenCoordinator(_ coordinator: TemplateScreenCoordinatorType, didCompleteWithMessage message: String)
func templateScreenCoordinator(_ coordinator: TemplateScreenCoordinatorType, didCompleteWithUserDisplayName userDisplayName: String?)
func templateScreenCoordinatorDidCancel(_ coordinator: TemplateScreenCoordinatorType)
}

View file

@ -18,7 +18,7 @@ import Foundation
/// TemplateScreenViewController view actions exposed to view model
enum TemplateScreenViewAction {
case sayHello
case loadData
case complete
case cancel
}

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="V8j-Lb-PgC">
<device id="retina4_7" orientation="portrait">
<device id="retina6_1" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
@ -15,36 +15,41 @@
<objects>
<viewController extendedLayoutIncludesOpaqueBars="YES" automaticallyAdjustsScrollViewInsets="NO" id="V8j-Lb-PgC" customClass="TemplateScreenViewController" customModule="Riot" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="EL9-GA-lwo">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="9U2-KL-ZVA">
<rect key="frame" x="0.0" y="20" width="375" height="647"/>
<rect key="frame" x="0.0" y="44" width="414" height="852"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="e7g-um-WO4">
<rect key="frame" x="0.0" y="0.0" width="375" height="500"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="208"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="voD-3Q-ryt">
<rect key="frame" x="0.0" y="0.0" width="375" height="500"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="208"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="A message" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bxI-mu-qng">
<rect key="frame" x="20" y="86" width="335" height="108"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="A message" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bxI-mu-qng">
<rect key="frame" x="20" y="40" width="374" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="DOt-5E-FjF">
<rect key="frame" x="104" y="368" width="167" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="DOt-5E-FjF">
<rect key="frame" x="20" y="158" width="374" height="30"/>
<state key="normal" title="OK"/>
<connections>
<action selector="okButtonAction:" destination="V8j-Lb-PgC" eventType="touchUpInside" id="uvI-tt-Nfj"/>
<action selector="doneButtonAction:" destination="V8j-Lb-PgC" eventType="touchUpInside" id="uvI-tt-Nfj"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="bxI-mu-qng" secondAttribute="trailing" constant="20" id="2v5-vH-NEd"/>
<constraint firstItem="DOt-5E-FjF" firstAttribute="top" secondItem="bxI-mu-qng" secondAttribute="bottom" constant="100" id="C4r-0w-VXj"/>
<constraint firstItem="bxI-mu-qng" firstAttribute="leading" secondItem="voD-3Q-ryt" secondAttribute="leading" constant="20" id="I1A-QW-IJG"/>
<constraint firstAttribute="trailing" secondItem="DOt-5E-FjF" secondAttribute="trailing" constant="20" id="NKP-2G-Czj"/>
<constraint firstItem="bxI-mu-qng" firstAttribute="top" secondItem="voD-3Q-ryt" secondAttribute="top" constant="40" id="bU7-a2-LIj"/>
<constraint firstAttribute="bottom" secondItem="DOt-5E-FjF" secondAttribute="bottom" constant="20" id="dmC-vE-FeB"/>
<constraint firstItem="DOt-5E-FjF" firstAttribute="leading" secondItem="voD-3Q-ryt" secondAttribute="leading" constant="20" id="flU-tM-8hK"/>
<constraint firstAttribute="width" priority="750" constant="500" id="glD-Sz-73O"/>
</constraints>
</view>
@ -55,7 +60,6 @@
<constraint firstItem="voD-3Q-ryt" firstAttribute="centerX" secondItem="e7g-um-WO4" secondAttribute="centerX" id="P2G-mq-gQW"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="voD-3Q-ryt" secondAttribute="trailing" id="QgV-SO-5yf"/>
<constraint firstItem="voD-3Q-ryt" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="e7g-um-WO4" secondAttribute="leading" id="YPo-u1-PtT"/>
<constraint firstAttribute="height" constant="500" id="n8g-KW-BYU"/>
<constraint firstItem="voD-3Q-ryt" firstAttribute="top" secondItem="e7g-um-WO4" secondAttribute="top" id="rhQ-96-szL"/>
</constraints>
</view>
@ -63,7 +67,7 @@
<constraints>
<constraint firstAttribute="trailing" secondItem="e7g-um-WO4" secondAttribute="trailing" id="GyG-Fh-PME"/>
<constraint firstItem="e7g-um-WO4" firstAttribute="width" secondItem="9U2-KL-ZVA" secondAttribute="width" id="Ok2-WQ-Zgc"/>
<constraint firstAttribute="bottom" secondItem="e7g-um-WO4" secondAttribute="bottom" constant="147" id="Y46-NP-zAc"/>
<constraint firstAttribute="bottom" secondItem="e7g-um-WO4" secondAttribute="bottom" id="Y46-NP-zAc"/>
<constraint firstItem="e7g-um-WO4" firstAttribute="leading" secondItem="9U2-KL-ZVA" secondAttribute="leading" id="aoV-Yh-AcD"/>
<constraint firstItem="e7g-um-WO4" firstAttribute="top" secondItem="9U2-KL-ZVA" secondAttribute="top" id="pFN-bA-SHw"/>
</constraints>
@ -79,8 +83,8 @@
<viewLayoutGuide key="safeArea" id="bFg-jh-JZB"/>
</view>
<connections>
<outlet property="messageLabel" destination="bxI-mu-qng" id="pbX-aZ-inC"/>
<outlet property="okButton" destination="DOt-5E-FjF" id="ktw-U4-efQ"/>
<outlet property="doneButton" destination="DOt-5E-FjF" id="ktw-U4-efQ"/>
<outlet property="informationLabel" destination="bxI-mu-qng" id="pbX-aZ-inC"/>
<outlet property="scrollView" destination="9U2-KL-ZVA" id="ojG-2y-X7b"/>
</connections>
</viewController>

View file

@ -30,8 +30,8 @@ final class TemplateScreenViewController: UIViewController {
@IBOutlet private weak var scrollView: UIScrollView!
@IBOutlet private weak var messageLabel: UILabel!
@IBOutlet private weak var okButton: UIButton!
@IBOutlet private weak var informationLabel: UILabel!
@IBOutlet private weak var doneButton: UIButton!
// MARK: Private
@ -57,8 +57,6 @@ final class TemplateScreenViewController: UIViewController {
// Do any additional setup after loading the view.
self.title = "Template"
self.setupViews()
self.keyboardAvoider = KeyboardAvoider(scrollViewContainerView: self.view, scrollView: self.scrollView)
self.activityPresenter = ActivityIndicatorPresenter()
@ -69,7 +67,7 @@ final class TemplateScreenViewController: UIViewController {
self.viewModel.viewDelegate = self
self.viewModel.process(viewAction: .sayHello)
self.viewModel.process(viewAction: .loadData)
}
override func viewWillAppear(_ animated: Bool) {
@ -100,11 +98,11 @@ final class TemplateScreenViewController: UIViewController {
}
// TODO:
self.messageLabel.textColor = theme.textPrimaryColor
// TODO: Set view colors here
self.informationLabel.textColor = theme.textPrimaryColor
self.okButton.backgroundColor = theme.backgroundColor
theme.applyStyle(onButton: self.okButton)
self.doneButton.backgroundColor = theme.backgroundColor
theme.applyStyle(onButton: self.doneButton)
}
private func registerThemeServiceDidChangeThemeNotification() {
@ -122,18 +120,19 @@ final class TemplateScreenViewController: UIViewController {
self.navigationItem.rightBarButtonItem = cancelBarButtonItem
self.title = "Template"
self.scrollView.keyboardDismissMode = .interactive
self.messageLabel.text = "VectorL10n.templateScreenTitle"
self.messageLabel.isHidden = true
self.informationLabel.text = "VectorL10n.templateScreenTitle"
}
private func render(viewState: TemplateScreenViewState) {
switch viewState {
case .loading:
self.renderLoading()
case .loaded:
self.renderLoaded()
case .loaded(let displayName):
self.renderLoaded(displayName: displayName)
case .error(let error):
self.render(error: error)
}
@ -141,13 +140,13 @@ final class TemplateScreenViewController: UIViewController {
private func renderLoading() {
self.activityPresenter.presentActivityIndicator(on: self.view, animated: true)
self.informationLabel.text = "Fetch display name"
}
private func renderLoaded() {
private func renderLoaded(displayName: String) {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
self.messageLabel.text = self.viewModel.message
self.messageLabel.isHidden = false
self.informationLabel.text = "You display name: \(displayName)"
}
private func render(error: Error) {
@ -158,7 +157,7 @@ final class TemplateScreenViewController: UIViewController {
// MARK: - Actions
@IBAction private func okButtonAction(_ sender: Any) {
@IBAction private func doneButtonAction(_ sender: Any) {
self.viewModel.process(viewAction: .complete)
}

View file

@ -24,9 +24,10 @@ final class TemplateScreenViewModel: TemplateScreenViewModelType {
private let session: MXSession
// MARK: Public
private var currentOperation: MXHTTPOperation?
private var userDisplayName: String?
var message: String?
// MARK: Public
weak var viewDelegate: TemplateScreenViewModelViewDelegate?
weak var coordinatorDelegate: TemplateScreenViewModelCoordinatorDelegate?
@ -35,46 +36,45 @@ final class TemplateScreenViewModel: TemplateScreenViewModelType {
init(session: MXSession) {
self.session = session
self.message = nil
}
deinit {
self.cancelOperations()
}
// MARK: - Public
func process(viewAction: TemplateScreenViewAction) {
switch viewAction {
case .sayHello:
self.setupHelloMessage()
case .loadData:
self.loadData()
case .complete:
if let message = self.message {
self.coordinatorDelegate?.templateScreenViewModel(self, didCompleteWithMessage: message)
}
self.coordinatorDelegate?.templateScreenViewModel(self, didCompleteWithUserDisplayName: self.userDisplayName)
case .cancel:
self.cancelOperations()
self.coordinatorDelegate?.templateScreenViewModelDidCancel(self)
}
}
// MARK: - Private
private func setupHelloMessage() {
private func loadData() {
self.update(viewState: .loading)
// Check first that the user homeserver is federated with the Riot-bot homeserver
self.session.matrixRestClient.displayName(forUser: self.session.myUser.userId) { [weak self] (response) in
self.currentOperation = self.session.matrixRestClient.displayName(forUser: self.session.myUser.userId) { [weak self] (response) in
guard let sself = self else {
guard let self = self else {
return
}
switch response {
case .success:
sself.message = "Hello \(response.value ?? "you")"
sself.update(viewState: .loaded)
case .success(let userDisplayName):
self.update(viewState: .loaded(userDisplayName))
self.userDisplayName = userDisplayName
case .failure(let error):
sself.update(viewState: .error(error))
self.update(viewState: .error(error))
}
}
}
@ -82,4 +82,8 @@ final class TemplateScreenViewModel: TemplateScreenViewModelType {
private func update(viewState: TemplateScreenViewState) {
self.viewDelegate?.templateScreenViewModel(self, didUpdateViewState: viewState)
}
private func cancelOperations() {
self.currentOperation?.cancel()
}
}

View file

@ -21,15 +21,13 @@ protocol TemplateScreenViewModelViewDelegate: class {
}
protocol TemplateScreenViewModelCoordinatorDelegate: class {
func templateScreenViewModel(_ viewModel: TemplateScreenViewModelType, didCompleteWithMessage message: String)
func templateScreenViewModel(_ viewModel: TemplateScreenViewModelType, didCompleteWithUserDisplayName userDisplayName: String?)
func templateScreenViewModelDidCancel(_ viewModel: TemplateScreenViewModelType)
}
/// Protocol describing the view model used by `TemplateScreenViewController`
protocol TemplateScreenViewModelType {
var message: String? { get set }
var viewDelegate: TemplateScreenViewModelViewDelegate? { get set }
var coordinatorDelegate: TemplateScreenViewModelCoordinatorDelegate? { get set }

View file

@ -19,6 +19,6 @@ import Foundation
/// TemplateScreenViewController view state
enum TemplateScreenViewState {
case loading
case loaded
case loaded(_ displayName: String)
case error(Error)
}