Merge branch 'release/v0.11.0'

This commit is contained in:
manuroe 2020-04-17 19:04:38 +02:00
commit bf15a78476
291 changed files with 16262 additions and 2924 deletions

View file

@ -6,4 +6,4 @@
* [ ] Pull request is based on the develop branch
* [ ] Pull request updates [CHANGES.rst](https://github.com/vector-im/riot-ios/blob/develop/CHANGES.rst)
* [ ] Pull request includes screenshots or videos of UI changes
* [ ] Pull request includes a [sign off](https://github.com/matrix-org/synapse/blob/master/CONTRIBUTING.rst#sign-off)
* [ ] Pull request includes a [sign off](https://github.com/matrix-org/synapse/blob/master/CONTRIBUTING.md#sign-off)

View file

@ -1,3 +1,27 @@
Changes in 0.11.0 (2020-04-17)
===============================================
Improvements:
* Upgrade MatrixKit version ([v0.12.0](https://github.com/matrix-org/matrix-ios-kit/releases/tag/v0.12.0)).
* Crypto: Enable E2EE by default for DM
* Crypto: Cross-signing support
* Crypto: Do not warn anymore for unknown devices. Trust on First Use.
* RoomVC: Update encryption decoration with shields (#2934, #2930, #2906).
* Settings: Remove "End-to-End Encryption" from the LABS section (#2941).
* Room decoration: Use shields instead of padlocks (#2906).
* Room decoration: Remove horizontal empty space when there is no decoration badge to set on room message (#2978).
* RoomVC: For a room preview use room canonical alias if present when joining a room.
* Update Matomo app id (#3001)
* Verification by DM: Support QR code (#2921).
* Cross-Signing: Detect and expose new sign-ins (#2918).
* Cross-signing: Complete security at the end of sign in process( #3003).
* Make decoration uniform (#2972).
* DeactivateAccountViewController: Respect active theme (PR #3107).
* Verification by emojis: Center emojis in screen horizontally (PR #3119).
Bug fix:
* Key backup banner is not hidden correctly (#2899).
Changes in 0.10.5 (2020-04-01)
===============================================
@ -5,7 +29,7 @@ Bug fix:
* Fix error when joining some public rooms, thanks to @chrismoos (PR #2888).
* Fix crash due to malformed widget (#2997).
* Push notifications: Avoid any automatic deactivation (vector-im/riot-ios#3017).
* Fix links breaking user out of SSO flow.
* Fix links breaking user out of SSO flow, thanks to @schultetwin (#3039).
Changes in 0.10.4 (2019-12-11)
===============================================

View file

@ -1,4 +1,4 @@
Contributing code to Riot iOS
==================================
riot-ios follows the same pattern as https://github.com/matrix-org/synapse/blob/master/CONTRIBUTING.rst
riot-ios follows the same pattern as https://github.com/matrix-org/synapse/blob/master/CONTRIBUTING.md

View file

@ -7,7 +7,7 @@ use_frameworks!
# Different flavours of pods to MatrixKit
# The current MatrixKit pod version
$matrixKitVersion = '0.11.4'
$matrixKitVersion = '0.12.0'
# The develop branch version
#$matrixKitVersion = 'develop'
@ -61,8 +61,7 @@ abstract_target 'RiotPods' do
pod 'GBDeviceInfo', '~> 6.3.0'
pod 'Reusable', '~> 4.1'
pod 'SwiftUTI', :git => 'https://github.com/speramusinc/SwiftUTI.git', :branch => 'master'
# Piwik for analytics
pod 'MatomoTracker', '~> 7.2.0'
@ -77,7 +76,9 @@ abstract_target 'RiotPods' do
target "Riot" do
import_MatrixKit
pod 'DGCollectionViewLeftAlignFlowLayout', '~> 1.0.4'
pod 'DGCollectionViewLeftAlignFlowLayout', '~> 1.0.4'
pod 'KTCenterFlowLayout', '~> 1.3.1'
pod 'ZXingObjC', '~> 3.6.5'
target 'RiotTests' do
inherit! :search_paths

View file

@ -44,46 +44,44 @@ PODS:
- GZIP (1.2.3)
- HPGrowingTextView (1.1)
- JitsiMeetSDK (2.3.1)
- KTCenterFlowLayout (1.3.1)
- libbase58 (0.1.4)
- libPhoneNumber-iOS (0.9.15)
- MatomoTracker (7.2.0):
- MatomoTracker/Core (= 7.2.0)
- MatomoTracker/Core (7.2.0)
- MatrixKit (0.11.4):
- MatrixKit (0.12.0):
- cmark (~> 0.24.1)
- DTCoreText (~> 1.6.21)
- HPGrowingTextView (~> 1.1)
- libPhoneNumber-iOS (~> 0.9.13)
- MatrixKit/Core (= 0.11.4)
- MatrixSDK (= 0.15.2)
- SwiftUTI (~> 1.0.6)
- MatrixKit/AppExtension (0.11.4):
- MatrixKit/Core (= 0.12.0)
- MatrixSDK (= 0.16.0)
- MatrixKit/AppExtension (0.12.0):
- cmark (~> 0.24.1)
- DTCoreText (~> 1.6.21)
- DTCoreText/Extension
- HPGrowingTextView (~> 1.1)
- libPhoneNumber-iOS (~> 0.9.13)
- MatrixSDK (= 0.15.2)
- SwiftUTI (~> 1.0.6)
- MatrixKit/Core (0.11.4):
- MatrixSDK (= 0.16.0)
- MatrixKit/Core (0.12.0):
- cmark (~> 0.24.1)
- DTCoreText (~> 1.6.21)
- HPGrowingTextView (~> 1.1)
- libPhoneNumber-iOS (~> 0.9.13)
- MatrixSDK (= 0.15.2)
- SwiftUTI (~> 1.0.6)
- MatrixSDK (0.15.2):
- MatrixSDK/Core (= 0.15.2)
- MatrixSDK/Core (0.15.2):
- MatrixSDK (= 0.16.0)
- MatrixSDK (0.16.0):
- MatrixSDK/Core (= 0.16.0)
- MatrixSDK/Core (0.16.0):
- AFNetworking (~> 3.2.0)
- GZIP (~> 1.2.2)
- libbase58 (~> 0.1.4)
- OLMKit (~> 3.1.0)
- Realm (~> 3.17.3)
- MatrixSDK/JingleCallStack (0.15.2):
- MatrixSDK/JingleCallStack (0.16.0):
- JitsiMeetSDK (~> 2.3.1)
- MatrixSDK/Core
- MatrixSDK/SwiftSupport (0.15.2):
- MatrixSDK/SwiftSupport (0.16.0):
- MatrixSDK/Core
- OLMKit (3.1.0):
- OLMKit/olmc (= 3.1.0)
@ -100,24 +98,27 @@ PODS:
- Reusable/View (4.1.0)
- SwiftGen (6.1.0)
- SwiftLint (0.36.0)
- SwiftUTI (1.0.7)
- zxcvbn-ios (1.0.4)
- ZXingObjC (3.6.5):
- ZXingObjC/All (= 3.6.5)
- ZXingObjC/All (3.6.5)
DEPENDENCIES:
- cmark
- DGCollectionViewLeftAlignFlowLayout (~> 1.0.4)
- GBDeviceInfo (~> 6.3.0)
- KTCenterFlowLayout (~> 1.3.1)
- MatomoTracker (~> 7.2.0)
- MatrixKit (= 0.11.4)
- MatrixKit/AppExtension (= 0.11.4)
- MatrixKit (= 0.12.0)
- MatrixKit/AppExtension (= 0.12.0)
- MatrixSDK/JingleCallStack
- MatrixSDK/SwiftSupport
- OLMKit
- Reusable (~> 4.1)
- SwiftGen (~> 6.1)
- SwiftLint (~> 0.36.0)
- SwiftUTI (from `https://github.com/speramusinc/SwiftUTI.git`, branch `master`)
- zxcvbn-ios
- ZXingObjC (~> 3.6.5)
SPEC REPOS:
trunk:
@ -130,6 +131,7 @@ SPEC REPOS:
- GZIP
- HPGrowingTextView
- JitsiMeetSDK
- KTCenterFlowLayout
- libbase58
- libPhoneNumber-iOS
- MatomoTracker
@ -141,16 +143,7 @@ SPEC REPOS:
- SwiftGen
- SwiftLint
- zxcvbn-ios
EXTERNAL SOURCES:
SwiftUTI:
:branch: master
:git: https://github.com/speramusinc/SwiftUTI.git
CHECKOUT OPTIONS:
SwiftUTI:
:commit: b6b46942fb3aad819610851f62a70e17a528444e
:git: https://github.com/speramusinc/SwiftUTI.git
- ZXingObjC
SPEC CHECKSUMS:
AFNetworking: b6f891fdfaed196b46c7a83cf209e09697b94057
@ -162,19 +155,20 @@ SPEC CHECKSUMS:
GZIP: af5c90ef903776a7e9afe6ebebd794a84a2929d4
HPGrowingTextView: 88a716d97fb853bcb08a4a08e4727da17efc9b19
JitsiMeetSDK: 69e4978fbab21f9a535d1bec3b8d43721a4c72b2
KTCenterFlowLayout: 6e02b50ab2bd865025ae82fe266ed13b6d9eaf97
libbase58: 7c040313537b8c44b6e2d15586af8e21f7354efd
libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75
MatomoTracker: 6f89e2561083685a360e223fb663e9ccd57c1d1a
MatrixKit: 3db15f216e2de4d53b1405434028d44f42d4af22
MatrixSDK: f83bd3c5519c1cb9ac3998f6423574cf528f0250
MatrixKit: 2ae83c621caf3c11681e00a0b802086ac4d1106c
MatrixSDK: caad3d93c665163d9d414f6876e9a7d220c6c46f
OLMKit: 4ee0159d63feeb86d836fdcfefe418e163511639
Realm: 5a1d9d47bfc101dd597668b1a8af4288a2557f6d
Reusable: 82be188f29d96dc5eff0db7b2393bcc08d2cdd5b
SwiftGen: f872ca75cbd17bf7103c17f13dcfa0d9a15667b0
SwiftLint: fc9859e4e1752340664851f667bb1898b9c90114
SwiftUTI: 917993c124f8eac25e88ced0202fc58d7eb50fa8
zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
PODFILE CHECKSUM: c7b37d248a316ae786328d88148e3155fea6bee3
PODFILE CHECKSUM: 6f647ad2f6c765719fd7e9a5d1e9e77e797d328f
COCOAPODS: 1.8.4
COCOAPODS: 1.9.1

File diff suppressed because it is too large Load diff

View file

@ -130,6 +130,17 @@ extern NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey;
- (void)logoutSendingRequestServer:(BOOL)sendLogoutServerRequest
completion:(void (^)(BOOL isLoggedOut))completion;
/**
Present incoming key verification request to accept.
@param incomingKeyVerificationRequest The incoming key verification request.
@param The matrix session.
@return Indicate NO if the key verification screen could not be presented.
*/
- (BOOL)presentIncomingKeyVerificationRequest:(MXKeyVerificationRequest*)incomingKeyVerificationRequest
inSession:(MXSession*)session;
- (BOOL)presentUserVerificationForRoomMember:(MXRoomMember*)roomMember session:(MXSession*)mxSession;
#pragma mark - Matrix Accounts handling

View file

@ -88,7 +88,7 @@ NSString *const AppDelegateDidValidateEmailNotification = @"AppDelegateDidValida
NSString *const AppDelegateDidValidateEmailNotificationSIDKey = @"AppDelegateDidValidateEmailNotificationSIDKey";
NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDelegateDidValidateEmailNotificationClientSecretKey";
@interface AppDelegate () <PKPushRegistryDelegate, GDPRConsentViewControllerDelegate, DeviceVerificationCoordinatorBridgePresenterDelegate, ServiceTermsModalCoordinatorBridgePresenterDelegate>
@interface AppDelegate () <PKPushRegistryDelegate, GDPRConsentViewControllerDelegate, KeyVerificationCoordinatorBridgePresenterDelegate, ServiceTermsModalCoordinatorBridgePresenterDelegate>
{
/**
Reachability observer
@ -133,14 +133,14 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
RoomKeyRequestViewController *roomKeyRequestViewController;
/**
Incoming device verification requests observers
Incoming key verification requests observers
*/
id incomingDeviceVerificationObserver;
id incomingKeyVerificationObserver;
/**
If any the currently displayed device verification dialog
If any the currently displayed key verification dialog
*/
DeviceVerificationCoordinatorBridgePresenter *deviceVerificationCoordinatorBridgePresenter;
KeyVerificationCoordinatorBridgePresenter *keyVerificationCoordinatorBridgePresenter;
/**
Account picker used in case of multiple account.
@ -237,6 +237,8 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
@property (weak, nonatomic) UIAlertController *gdprConsentNotGivenAlertController;
@property (weak, nonatomic) UIViewController *gdprConsentController;
@property (weak, nonatomic) UIAlertController *incomingKeyVerificationRequestAlertController;
@property (nonatomic, strong) ServiceTermsModalCoordinatorBridgePresenter *serviceTermsModalCoordinatorBridgePresenter;
@property (nonatomic, strong) SlidingModalPresenter *slidingModalPresenter;
@ -251,6 +253,9 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
@property (nonatomic, strong) PKPushRegistry *pushRegistry;
@property (nonatomic) NSMutableDictionary <NSNumber *, NSMutableArray <NSString *> *> *incomingPushEventIds;
@property (nonatomic, weak) id userDidSignInOnNewDeviceObserver;
@property (weak, nonatomic) UIAlertController *userNewSignInAlertController;
@end
@implementation AppDelegate
@ -264,11 +269,12 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
// Set the App Group identifier.
MXSDKOptions *sdkOptions = [MXSDKOptions sharedInstance];
sdkOptions.applicationGroupIdentifier = @"group.im.vector";
sdkOptions.computeE2ERoomSummaryTrust = YES;
// Redirect NSLogs to files only if we are not debugging
if (!isatty(STDERR_FILENO))
{
[MXLogger redirectNSLogToFiles:YES];
[MXLogger redirectNSLogToFiles:YES numberOfFiles:50];
}
NSLog(@"[AppDelegate] initialize: Done");
@ -973,18 +979,9 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
- (void)showNotificationAlert:(UIAlertController*)alert
{
if (self.window.rootViewController.presentedViewController)
{
[alert popoverPresentationController].sourceView = self.window.rootViewController.presentedViewController.view;
[alert popoverPresentationController].sourceRect = self.window.rootViewController.presentedViewController.view.bounds;
[self.window.rootViewController.presentedViewController presentViewController:alert animated:YES completion:nil];
}
else
{
[alert popoverPresentationController].sourceView = self.window.rootViewController.view;
[alert popoverPresentationController].sourceRect = self.window.rootViewController.view.bounds;
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
}
[alert popoverPresentationController].sourceView = self.presentedViewController.view;
[alert popoverPresentationController].sourceRect = self.presentedViewController.view.bounds;
[self.presentedViewController presentViewController:alert animated:YES completion:nil];
}
- (void)onSessionCryptoDidCorruptData:(NSNotification *)notification
@ -1600,132 +1597,6 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
return notificationUserInfo;
}
- (void)notificationBodyForEvent:(MXEvent *)event pushRule:(MXPushRule*)rule inAccount:(MXKAccount*)account onComplete:(void (^)(NSString * _Nullable notificationBody))onComplete;
{
if (!event.content || !event.content.count)
{
NSLog(@"[AppDelegate][Push] notificationBodyForEvent: empty event content");
onComplete (nil);
return;
}
MXRoom *room = [account.mxSession roomWithRoomId:event.roomId];
if (!room)
{
NSLog(@"[AppDelegate][Push] notificationBodyForEvent: Unknown room");
onComplete (nil);
return;
}
[room state:^(MXRoomState *roomState) {
NSString *notificationBody;
NSString *eventSenderName = [roomState.members memberName:event.sender];
if (event.eventType == MXEventTypeRoomMessage || event.eventType == MXEventTypeRoomEncrypted)
{
if (room.isMentionsOnly)
{
// A local notification will be displayed only for highlighted notification.
BOOL isHighlighted = NO;
// Check whether is there an highlight tweak on it
for (MXPushRuleAction *ruleAction in rule.actions)
{
if (ruleAction.actionType == MXPushRuleActionTypeSetTweak)
{
if ([ruleAction.parameters[@"set_tweak"] isEqualToString:@"highlight"])
{
// Check the highlight tweak "value"
// If not present, highlight. Else check its value before highlighting
if (nil == ruleAction.parameters[@"value"] || YES == [ruleAction.parameters[@"value"] boolValue])
{
isHighlighted = YES;
break;
}
}
}
}
if (!isHighlighted)
{
// Ignore this notif.
NSLog(@"[AppDelegate][Push] notificationBodyForEvent: Ignore non highlighted notif in mentions only room");
onComplete(nil);
return;
}
}
NSString *msgType = event.content[@"msgtype"];
NSString *content = event.content[@"body"];
if (event.isEncrypted && !RiotSettings.shared.showDecryptedContentInNotifications)
{
// Hide the content
msgType = nil;
}
NSString *roomDisplayName = room.summary.displayname;
// Display the room name only if it is different than the sender name
if (roomDisplayName.length && ![roomDisplayName isEqualToString:eventSenderName])
{
if ([msgType isEqualToString:@"m.text"])
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER_IN_ROOM_WITH_CONTENT", nil), eventSenderName,roomDisplayName, content];
else if ([msgType isEqualToString:@"m.emote"])
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"ACTION_FROM_USER_IN_ROOM", nil), roomDisplayName, eventSenderName, content];
else if ([msgType isEqualToString:@"m.image"])
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"IMAGE_FROM_USER_IN_ROOM", nil), eventSenderName, content, roomDisplayName];
else
// Encrypted messages falls here
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER_IN_ROOM", nil), eventSenderName, roomDisplayName];
}
else
{
if ([msgType isEqualToString:@"m.text"])
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER_WITH_CONTENT", nil), eventSenderName, content];
else if ([msgType isEqualToString:@"m.emote"])
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"ACTION_FROM_USER", nil), eventSenderName, content];
else if ([msgType isEqualToString:@"m.image"])
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"IMAGE_FROM_USER", nil), eventSenderName, content];
else
// Encrypted messages falls here
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER", nil), eventSenderName];
}
}
else if (event.eventType == MXEventTypeCallInvite)
{
NSString *sdp = event.content[@"offer"][@"sdp"];
BOOL isVideoCall = [sdp rangeOfString:@"m=video"].location != NSNotFound;
if (!isVideoCall)
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"VOICE_CALL_FROM_USER", nil), eventSenderName];
else
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"VIDEO_CALL_FROM_USER", nil), eventSenderName];
}
else if (event.eventType == MXEventTypeRoomMember)
{
NSString *roomDisplayName = room.summary.displayname;
if (roomDisplayName.length && ![roomDisplayName isEqualToString:eventSenderName])
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"USER_INVITE_TO_NAMED_ROOM", nil), eventSenderName, roomDisplayName];
else
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"USER_INVITE_TO_CHAT", nil), eventSenderName];
}
else if (event.eventType == MXEventTypeSticker)
{
NSString *roomDisplayName = room.summary.displayname;
if (roomDisplayName.length && ![roomDisplayName isEqualToString:eventSenderName])
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER_IN_ROOM", nil), eventSenderName, roomDisplayName];
else
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER", nil), eventSenderName];
}
onComplete(notificationBody);
}];
}
// iOS 10+, does the same thing as notificationBodyForEvent:pushRule:inAccount:onComplete:, except with more features
- (void)notificationContentForEvent:(MXEvent *)event pushRule:(MXPushRule *)rule inAccount:(MXKAccount *)account onComplete:(void (^)(UNNotificationContent * _Nullable notificationContent))onComplete;
{
@ -1751,6 +1622,7 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
NSString *threadIdentifier = room.roomId;
NSString *eventSenderName = [roomState.members memberName:event.sender];
NSString *currentUserId = account.mxCredentials.userId;
if (event.eventType == MXEventTypeRoomMessage || event.eventType == MXEventTypeRoomEncrypted)
{
@ -1797,6 +1669,9 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
NSString *roomDisplayName = room.summary.displayname;
NSString *myUserId = account.mxSession.myUser.userId;
BOOL isIncomingEvent = ![event.sender isEqualToString:myUserId];
// Display the room name only if it is different than the sender name
if (roomDisplayName.length && ![roomDisplayName isEqualToString:eventSenderName])
{
@ -1814,6 +1689,30 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
{
notificationBody = [NSString localizedUserNotificationStringForKey:@"IMAGE_FROM_USER" arguments:@[eventSenderName, messageContent]];
}
else if (room.isDirect && isIncomingEvent && [msgType isEqualToString:kMXMessageTypeKeyVerificationRequest])
{
[account.mxSession.crypto.keyVerificationManager keyVerificationFromKeyVerificationEvent:event
success:^(MXKeyVerification * _Nonnull keyVerification)
{
if (keyVerification && keyVerification.state == MXKeyVerificationRequestStatePending)
{
// TODO: Add accept and decline actions to notification
NSString *body = [NSString localizedUserNotificationStringForKey:@"KEY_VERIFICATION_REQUEST_FROM_USER" arguments:@[eventSenderName]];
UNNotificationContent *notificationContent = [self notificationContentWithTitle:notificationTitle
body:body
threadIdentifier:threadIdentifier
userId:currentUserId
event:event
pushRule:rule];
onComplete(notificationContent);
}
} failure:^(NSError * _Nonnull error) {
NSLog(@"[AppDelegate][Push] notificationContentForEvent: failed to fetch key verification with error: %@", error);
}];
}
else
{
// Encrypted messages falls here
@ -1889,27 +1788,47 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
notificationBody = [NSString localizedUserNotificationStringForKey:@"STICKER_FROM_USER" arguments:@[eventSenderName]];
}
UNMutableNotificationContent *notificationContent = [[UNMutableNotificationContent alloc] init];
NSDictionary *notificationUserInfo = [self notificationUserInfoForEvent:event andUserId:account.mxCredentials.userId];
NSString *notificationSoundName = [self notificationSoundNameFromPushRule:rule];
NSString *categoryIdentifier = [self notificationCategoryIdentifierForEvent:event];
notificationContent.title = notificationTitle;
notificationContent.body = notificationBody;
notificationContent.threadIdentifier = threadIdentifier;
notificationContent.userInfo = notificationUserInfo;
notificationContent.categoryIdentifier = categoryIdentifier;
if (notificationSoundName)
if (notificationBody)
{
notificationContent.sound = [UNNotificationSound soundNamed:notificationSoundName];
UNNotificationContent *notificationContent = [self notificationContentWithTitle:notificationTitle
body:notificationBody
threadIdentifier:threadIdentifier
userId:currentUserId
event:event
pushRule:rule];
onComplete(notificationContent);
}
onComplete([notificationContent copy]);
}];
}
- (UNNotificationContent*)notificationContentWithTitle:(NSString*)title
body:(NSString*)body
threadIdentifier:(NSString*)threadIdentifier
userId:(NSString*)userId
event:(MXEvent*)event
pushRule:(MXPushRule*)pushRule
{
UNMutableNotificationContent *notificationContent = [[UNMutableNotificationContent alloc] init];
NSDictionary *notificationUserInfo = [self notificationUserInfoForEvent:event andUserId:userId];
NSString *notificationSoundName = [self notificationSoundNameFromPushRule:pushRule];
NSString *categoryIdentifier = [self notificationCategoryIdentifierForEvent:event];
notificationContent.title = title;
notificationContent.body = body;
notificationContent.threadIdentifier = threadIdentifier;
notificationContent.userInfo = notificationUserInfo;
notificationContent.categoryIdentifier = categoryIdentifier;
if (notificationSoundName)
{
notificationContent.sound = [UNNotificationSound soundNamed:notificationSoundName];
}
return [notificationContent copy];
}
/**
Display "limited" notifications for events the app was not able to get data
(because of /sync failure).
@ -2799,6 +2718,15 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
break;
}
}
// Do not warn for unknown devices. We have cross-signing now
mxSession.crypto.warnOnUnknowDevices = NO;
// Register to user new device sign in notification
[self registerUserDidSignInOnNewDeviceNotificationForSession:mxSession];
// Register to new key verification request
[self registerNewRequestNotificationForSession:mxSession];
}
else if (mxSession.state == MXSessionStateClosed)
{
@ -2858,7 +2786,7 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
{
// Check if we need to display a key share dialog
[self checkPendingRoomKeyRequests];
[self checkPendingIncomingDeviceVerificationsInSession:mxSession];
[self checkPendingIncomingKeyVerificationsInSession:mxSession];
}
}
@ -3050,8 +2978,8 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
// Enable listening of incoming key share requests
[self enableRoomKeyRequestObserver:mxSession];
// Enable listening of incoming device verification requests
[self enableIncomingDeviceVerificationObserver:mxSession];
// Enable listening of incoming key verification requests
[self enableIncomingKeyVerificationObserver:mxSession];
}
}
@ -3074,8 +3002,8 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
// Disable listening of incoming key share requests
[self disableRoomKeyRequestObserver:mxSession];
// Disable listening of incoming device verification requests
[self disableIncomingDeviceVerificationObserver:mxSession];
// Disable listening of incoming key verification requests
[self disableIncomingKeyVerificationObserver:mxSession];
[mxSessionArray removeObject:mxSession];
@ -3611,6 +3539,18 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
}
}
- (void)presentViewController:(UIViewController*)viewController
animated:(BOOL)animated
completion:(void (^)(void))completion
{
[self.presentedViewController presentViewController:viewController animated:animated completion:completion];
}
- (UIViewController*)presentedViewController
{
return self.window.rootViewController.presentedViewController ?: self.window.rootViewController;
}
#pragma mark - Matrix Accounts handling
- (void)enableInAppNotificationsForAccount:(MXKAccount*)account
@ -3838,38 +3778,46 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
{
// Create a new room by inviting the other user only if it is defined and not oneself
NSArray *invite = ((userId && ![mxSession.myUser.userId isEqualToString:userId]) ? @[userId] : nil);
[mxSession createRoom:nil
visibility:kMXRoomDirectoryVisibilityPrivate
roomAlias:nil
topic:nil
invite:invite
invite3PID:nil
isDirect:(invite.count != 0)
preset:kMXRoomPresetTrustedPrivateChat
success:^(MXRoom *room) {
// Open created room
[self showRoom:room.roomId andEventId:nil withMatrixSession:mxSession];
if (completion)
{
completion();
}
}
failure:^(NSError *error) {
NSLog(@"[AppDelegate] Create direct chat failed");
//Alert user
[self showErrorAsAlert:error];
if (completion)
{
completion();
}
}];
void (^onFailure)(NSError *) = ^(NSError *error){
NSLog(@"[AppDelegate] Create direct chat failed");
//Alert user
[self showErrorAsAlert:error];
if (completion)
{
completion();
}
};
[mxSession canEnableE2EByDefaultInNewRoomWithUsers:invite success:^(BOOL canEnableE2E) {
MXRoomCreationParameters *roomCreationParameters = [MXRoomCreationParameters new];
roomCreationParameters.visibility = kMXRoomDirectoryVisibilityPrivate;
roomCreationParameters.inviteArray = invite;
roomCreationParameters.isDirect = (invite.count != 0);
roomCreationParameters.preset = kMXRoomPresetTrustedPrivateChat;
if (canEnableE2E)
{
roomCreationParameters.initialStateEvents = @[
[MXRoomCreationParameters initialStateEventForEncryptionWithAlgorithm:kMXCryptoMegolmAlgorithm
]];
}
[mxSession createRoomWithParameters:roomCreationParameters success:^(MXRoom *room) {
// Open created room
[self showRoom:room.roomId andEventId:nil withMatrixSession:mxSession];
if (completion)
{
completion();
}
} failure:onFailure];
} failure:onFailure];
}
else if (completion)
{
@ -3951,13 +3899,7 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
{
[MXKAppSettings standardAppSettings].syncLocalContactsPermissionRequested = YES;
UIViewController *viewController = self.window.rootViewController.presentedViewController;
if (!viewController)
{
viewController = self.window.rootViewController;
}
[MXKContactManager requestUserConfirmationForLocalContactsSyncInViewController:viewController completionHandler:^(BOOL granted) {
[MXKContactManager requestUserConfirmationForLocalContactsSyncInViewController:self.presentedViewController completionHandler:^(BOOL granted) {
if (granted)
{
@ -4139,14 +4081,7 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
if (_jitsiViewController)
{
if (self.window.rootViewController.presentedViewController)
{
[self.window.rootViewController.presentedViewController presentViewController:_jitsiViewController animated:YES completion:completion];
}
else
{
[self.window.rootViewController presentViewController:_jitsiViewController animated:YES completion:completion];
}
[self presentViewController:_jitsiViewController animated:YES completion:completion];
}
}
@ -4288,10 +4223,8 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
}];
};
UIViewController *presentingViewController = self.window.rootViewController.presentedViewController ?: self.window.rootViewController;
[self.slidingModalPresenter present:widgetPermissionViewController
from:presentingViewController
from:self.presentedViewController
animated:YES
completion:nil];
}
@ -4389,14 +4322,7 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
if (currentCallViewController)
{
if (self.window.rootViewController.presentedViewController)
{
[self.window.rootViewController.presentedViewController presentViewController:currentCallViewController animated:animated completion:completion];
}
else
{
[self.window.rootViewController presentViewController:currentCallViewController animated:animated completion:completion];
}
[self presentViewController:currentCallViewController animated:animated completion:completion];
}
}
@ -4705,12 +4631,12 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
NSString *deviceId = [pendingKeyRequests deviceIdsForUser:userId].firstObject;
// Give the client a chance to refresh the device list
[mxSession.crypto downloadKeys:@[userId] forceDownload:NO success:^(MXUsersDevicesMap<MXDeviceInfo *> *usersDevicesInfoMap) {
[mxSession.crypto downloadKeys:@[userId] forceDownload:NO success:^(MXUsersDevicesMap<MXDeviceInfo *> *usersDevicesInfoMap, NSDictionary<NSString *,MXCrossSigningInfo *> *crossSigningKeysMap) {
MXDeviceInfo *deviceInfo = [usersDevicesInfoMap objectForDevice:deviceId forUser:userId];
if (deviceInfo)
{
BOOL wasNewDevice = (deviceInfo.verified == MXDeviceUnknown);
BOOL wasNewDevice = (deviceInfo.trustLevel.localVerificationStatus == MXDeviceUnknown);
void (^openDialog)(void) = ^void()
{
@ -4766,54 +4692,54 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
}
}
#pragma mark - Incoming device verification requests handling
#pragma mark - Incoming key verification handling
- (void)enableIncomingDeviceVerificationObserver:(MXSession*)mxSession
- (void)enableIncomingKeyVerificationObserver:(MXSession*)mxSession
{
incomingDeviceVerificationObserver =
[[NSNotificationCenter defaultCenter] addObserverForName:MXDeviceVerificationManagerNewTransactionNotification
object:mxSession.crypto.deviceVerificationManager
incomingKeyVerificationObserver =
[[NSNotificationCenter defaultCenter] addObserverForName:MXKeyVerificationManagerNewTransactionNotification
object:mxSession.crypto.keyVerificationManager
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *notif)
{
NSObject *object = notif.userInfo[MXDeviceVerificationManagerNotificationTransactionKey];
NSObject *object = notif.userInfo[MXKeyVerificationManagerNotificationTransactionKey];
if ([object isKindOfClass:MXIncomingSASTransaction.class])
{
[self checkPendingIncomingDeviceVerificationsInSession:mxSession];
[self checkPendingIncomingKeyVerificationsInSession:mxSession];
}
}];
}
- (void)disableIncomingDeviceVerificationObserver:(MXSession*)mxSession
- (void)disableIncomingKeyVerificationObserver:(MXSession*)mxSession
{
if (incomingDeviceVerificationObserver)
if (incomingKeyVerificationObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:incomingDeviceVerificationObserver];
incomingDeviceVerificationObserver = nil;
[[NSNotificationCenter defaultCenter] removeObserver:incomingKeyVerificationObserver];
incomingKeyVerificationObserver = nil;
}
}
// Check if an incoming device verification dialog must be displayed for the given session
- (void)checkPendingIncomingDeviceVerificationsInSession:(MXSession*)mxSession
// Check if an incoming key verification dialog must be displayed for the given session
- (void)checkPendingIncomingKeyVerificationsInSession:(MXSession*)mxSession
{
if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive)
{
NSLog(@"[AppDelegate][MXKeyVerification] checkPendingIncomingDeviceVerificationsInSession: called while the app is not active. Ignore it.");
NSLog(@"[AppDelegate][MXKeyVerification] checkPendingIncomingKeyVerificationsInSession: called while the app is not active. Ignore it.");
return;
}
[mxSession.crypto.deviceVerificationManager transactions:^(NSArray<MXDeviceVerificationTransaction *> * _Nonnull transactions) {
[mxSession.crypto.keyVerificationManager transactions:^(NSArray<MXKeyVerificationTransaction *> * _Nonnull transactions) {
NSLog(@"[AppDelegate][MXKeyVerification] checkPendingIncomingDeviceVerificationsInSession: transactions: %@", transactions);
NSLog(@"[AppDelegate][MXKeyVerification] checkPendingIncomingKeyVerificationsInSession: transactions: %@", transactions);
for (MXDeviceVerificationTransaction *transaction in transactions)
for (MXKeyVerificationTransaction *transaction in transactions)
{
if (transaction.isIncoming)
{
MXIncomingSASTransaction *incomingTransaction = (MXIncomingSASTransaction*)transaction;
if (incomingTransaction.state == MXSASTransactionStateIncomingShowAccept)
{
[self presentIncomingDeviceVerification:incomingTransaction inSession:mxSession];
[self presentIncomingKeyVerification:incomingTransaction inSession:mxSession];
break;
}
}
@ -4821,45 +4747,333 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
}];
}
// Check all opened MXSessions for incoming device verification dialog
- (void)checkPendingIncomingDeviceVerifications
// Check all opened MXSessions for incoming key verification dialog
- (void)checkPendingIncomingKeyVerifications
{
for (MXSession *mxSession in mxSessionArray)
{
[self checkPendingIncomingDeviceVerificationsInSession:mxSession];
[self checkPendingIncomingKeyVerificationsInSession:mxSession];
}
}
- (BOOL)presentIncomingDeviceVerification:(MXIncomingSASTransaction*)transaction inSession:(MXSession*)mxSession
- (BOOL)presentIncomingKeyVerificationRequest:(MXKeyVerificationRequest*)incomingKeyVerificationRequest
inSession:(MXSession*)session
{
NSLog(@"[AppDelegate][MXKeyVerification] presentIncomingDeviceVerification: %@", transaction);
BOOL presented = NO;
if (!keyVerificationCoordinatorBridgePresenter)
{
NSLog(@"[AppDelegate] presentIncomingKeyVerificationRequest");
keyVerificationCoordinatorBridgePresenter = [[KeyVerificationCoordinatorBridgePresenter alloc] initWithSession:session];
keyVerificationCoordinatorBridgePresenter.delegate = self;
[keyVerificationCoordinatorBridgePresenter presentFrom:self.presentedViewController incomingKeyVerificationRequest:incomingKeyVerificationRequest animated:YES];
presented = YES;
}
else
{
NSLog(@"[AppDelegate][MXKeyVerification] presentIncomingKeyVerificationRequest: Controller already presented.");
}
return presented;
}
- (BOOL)presentIncomingKeyVerification:(MXIncomingSASTransaction*)transaction inSession:(MXSession*)mxSession
{
NSLog(@"[AppDelegate][MXKeyVerification] presentIncomingKeyVerification: %@", transaction);
BOOL presented = NO;
if (!deviceVerificationCoordinatorBridgePresenter)
if (!keyVerificationCoordinatorBridgePresenter)
{
UIViewController *presentingViewController = self.window.rootViewController.presentedViewController ?: self.window.rootViewController;
keyVerificationCoordinatorBridgePresenter = [[KeyVerificationCoordinatorBridgePresenter alloc] initWithSession:mxSession];
keyVerificationCoordinatorBridgePresenter.delegate = self;
deviceVerificationCoordinatorBridgePresenter = [[DeviceVerificationCoordinatorBridgePresenter alloc] initWithSession:mxSession];
deviceVerificationCoordinatorBridgePresenter.delegate = self;
[deviceVerificationCoordinatorBridgePresenter presentFrom:presentingViewController incomingTransaction:transaction animated:YES];
[keyVerificationCoordinatorBridgePresenter presentFrom:self.presentedViewController incomingTransaction:transaction animated:YES];
presented = YES;
}
else
{
NSLog(@"[AppDelegate][MXKeyVerification] presentIncomingDeviceVerification: Controller already presented.");
NSLog(@"[AppDelegate][MXKeyVerification] presentIncomingKeyVerification: Controller already presented.");
}
return presented;
}
- (void)deviceVerificationCoordinatorBridgePresenterDelegateDidComplete:(DeviceVerificationCoordinatorBridgePresenter *)coordinatorBridgePresenter otherUserId:(NSString * _Nonnull)otherUserId otherDeviceId:(NSString * _Nonnull)otherDeviceId
- (BOOL)presentUserVerificationForRoomMember:(MXRoomMember*)roomMember session:(MXSession*)mxSession
{
[deviceVerificationCoordinatorBridgePresenter dismissWithAnimated:YES completion:^{
[self checkPendingIncomingDeviceVerifications];
NSLog(@"[AppDelegate][MXKeyVerification] presentUserVerificationForRoomMember: %@", roomMember);
BOOL presented = NO;
if (!keyVerificationCoordinatorBridgePresenter)
{
keyVerificationCoordinatorBridgePresenter = [[KeyVerificationCoordinatorBridgePresenter alloc] initWithSession:mxSession];
keyVerificationCoordinatorBridgePresenter.delegate = self;
[keyVerificationCoordinatorBridgePresenter presentFrom:self.presentedViewController roomMember:roomMember animated:YES];
presented = YES;
}
else
{
NSLog(@"[AppDelegate][MXKeyVerification] presentUserVerificationForRoomMember: Controller already presented.");
}
return presented;
}
- (BOOL)presentSelfVerificationForOtherDeviceId:(NSString*)deviceId inSession:(MXSession*)mxSession
{
NSLog(@"[AppDelegate][MXKeyVerification] presentSelfVerificationForOtherDeviceId: %@", deviceId);
BOOL presented = NO;
if (!keyVerificationCoordinatorBridgePresenter)
{
keyVerificationCoordinatorBridgePresenter = [[KeyVerificationCoordinatorBridgePresenter alloc] initWithSession:mxSession];
keyVerificationCoordinatorBridgePresenter.delegate = self;
[keyVerificationCoordinatorBridgePresenter presentFrom:self.presentedViewController otherUserId:mxSession.myUser.userId otherDeviceId:deviceId animated:YES];
presented = YES;
}
else
{
NSLog(@"[AppDelegate][MXKeyVerification] presentUserVerificationForRoomMember: Controller already presented.");
}
return presented;
}
- (void)keyVerificationCoordinatorBridgePresenterDelegateDidComplete:(KeyVerificationCoordinatorBridgePresenter *)coordinatorBridgePresenter otherUserId:(NSString * _Nonnull)otherUserId otherDeviceId:(NSString * _Nonnull)otherDeviceId
{
[self dismissKeyVerificationCoordinatorBridgePresenter];
}
- (void)keyVerificationCoordinatorBridgePresenterDelegateDidCancel:(KeyVerificationCoordinatorBridgePresenter * _Nonnull)coordinatorBridgePresenter
{
[self dismissKeyVerificationCoordinatorBridgePresenter];
}
- (void)dismissKeyVerificationCoordinatorBridgePresenter
{
[keyVerificationCoordinatorBridgePresenter dismissWithAnimated:YES completion:^{
[self checkPendingIncomingKeyVerifications];
}];
deviceVerificationCoordinatorBridgePresenter = nil;
keyVerificationCoordinatorBridgePresenter = nil;
}
#pragma mark - New request
- (void)registerNewRequestNotificationForSession:(MXSession*)session
{
MXKeyVerificationManager *keyverificationManager = session.crypto.keyVerificationManager;
if (!keyverificationManager)
{
return;
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyVerificationNewRequestNotification:) name:MXKeyVerificationManagerNewRequestNotification object:keyverificationManager];
}
- (void)keyVerificationNewRequestNotification:(NSNotification *)notification
{
if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground)
{
return;
}
NSDictionary *userInfo = notification.userInfo;
MXKeyVerificationRequest *keyVerificationRequest = userInfo[MXKeyVerificationManagerNotificationRequestKey];
if ([keyVerificationRequest isKindOfClass:MXKeyVerificationByDMRequest.class])
{
MXKeyVerificationByDMRequest *keyVerificationByDMRequest = (MXKeyVerificationByDMRequest*)keyVerificationRequest;
if (!keyVerificationByDMRequest.isFromMyUser && keyVerificationByDMRequest.state == MXKeyVerificationRequestStatePending)
{
MXKAccount *currentAccount = [MXKAccountManager sharedManager].activeAccounts.firstObject;
MXSession *session = currentAccount.mxSession;
MXRoom *room = [currentAccount.mxSession roomWithRoomId:keyVerificationByDMRequest.roomId];
if (!room)
{
NSLog(@"[AppDelegate][KeyVerification] keyVerificationRequestDidChangeNotification: Unknown room");
return;
}
NSString *sender = keyVerificationByDMRequest.otherUser;
[room state:^(MXRoomState *roomState) {
NSString *senderName = [roomState.members memberName:sender];
[self presentNewKeyVerificationRequestAlertForSession:session senderName:senderName senderId:sender request:keyVerificationByDMRequest];
}];
}
}
else if ([keyVerificationRequest isKindOfClass:MXKeyVerificationByToDeviceRequest.class])
{
MXKeyVerificationByToDeviceRequest *keyVerificationByToDeviceRequest = (MXKeyVerificationByToDeviceRequest*)keyVerificationRequest;
// We support only self verification
if (keyVerificationByToDeviceRequest.isFromMyUser
&& !keyVerificationByToDeviceRequest.isFromMyDevice
&& keyVerificationByToDeviceRequest.state == MXKeyVerificationRequestStatePending)
{
NSString *myUserId = keyVerificationByToDeviceRequest.otherUser;
MXKAccount *account = [[MXKAccountManager sharedManager] accountForUserId:myUserId];
if (account)
{
MXSession *session = account.mxSession;
MXUser *user = [session userWithUserId:myUserId];
[self presentNewKeyVerificationRequestAlertForSession:session senderName:user.displayname senderId:user.userId request:keyVerificationRequest];
}
}
}
}
- (void)presentNewKeyVerificationRequestAlertForSession:(MXSession*)session
senderName:(NSString*)senderName
senderId:(NSString*)senderId
request:(MXKeyVerificationRequest*)keyVerificationRequest
{
if (self.incomingKeyVerificationRequestAlertController)
{
[self.incomingKeyVerificationRequestAlertController dismissViewControllerAnimated:NO completion:nil];
}
NSString *senderInfo;
if (senderName)
{
senderInfo = [NSString stringWithFormat:@"%@ (%@)", senderName, senderId];
}
else
{
senderInfo = senderId;
}
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"key_verification_tile_request_incoming_title", @"Vector", nil)
message:senderInfo
preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"key_verification_tile_request_incoming_approval_accept", @"Vector", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
[self presentIncomingKeyVerificationRequest:keyVerificationRequest inSession:session];
}]];
[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"key_verification_tile_request_incoming_approval_decline", @"Vector", nil)
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction * action)
{
[keyVerificationRequest cancelWithCancelCode:MXTransactionCancelCode.user success:^{
} failure:^(NSError * _Nonnull error) {
NSLog(@"[AppDelegate][KeyVerification] Fail to cancel incoming key verification request with error: %@", error);
}];
}]];
[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"later", @"Vector", nil)
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action)
{
}]];
[self presentViewController:alertController animated:YES completion:nil];
self.incomingKeyVerificationRequestAlertController = alertController;
}
#pragma mark - New Sign In
- (void)registerUserDidSignInOnNewDeviceNotificationForSession:(MXSession*)session
{
MXCrossSigning *crossSigning = session.crypto.crossSigning;
if (!crossSigning)
{
return;
}
self.userDidSignInOnNewDeviceObserver = [NSNotificationCenter.defaultCenter addObserverForName:MXCrossSigningMyUserDidSignInOnNewDeviceNotification
object:crossSigning
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *notification)
{
NSArray<NSString*> *deviceIds = notification.userInfo[MXCrossSigningNotificationDeviceIdsKey];
[session.matrixRestClient devices:^(NSArray<MXDevice *> *devices) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF.deviceId IN %@", deviceIds];
NSArray<MXDevice*> *newDevices = [devices filteredArrayUsingPredicate:predicate];
NSArray *sortedDevices = [newDevices sortedArrayUsingComparator:^NSComparisonResult(MXDevice * _Nonnull device1, MXDevice * _Nonnull device2) {
if (device1.lastSeenTs == device2.lastSeenTs)
{
return NSOrderedSame;
}
return device1.lastSeenTs > device2.lastSeenTs ? NSOrderedDescending : NSOrderedAscending;
}];
MXDevice *mostRecentDevice = sortedDevices.lastObject;
if (mostRecentDevice)
{
[self presentNewSignInAlertForDevice:mostRecentDevice inSession:session];
}
} failure:^(NSError *error) {
NSLog(@"[AppDelegate][NewSignIn] Fail to fetch devices");
}];
}];
}
- (void)presentNewSignInAlertForDevice:(MXDevice*)device inSession:(MXSession*)session
{
if (self.userNewSignInAlertController)
{
return;
}
NSString *deviceInfo;
if (device.displayName)
{
deviceInfo = [NSString stringWithFormat:@"%@ (%@)", device.displayName, device.deviceId];
}
else
{
deviceInfo = device.deviceId;
}
NSString *alertMessage = [NSString stringWithFormat:NSLocalizedStringFromTable(@"device_verification_self_verify_alert_message", @"Vector", nil), deviceInfo];
UIAlertController *alert = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"device_verification_self_verify_alert_title", @"Vector", nil)
message:alertMessage
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"continue", @"Vector", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
[self presentSelfVerificationForOtherDeviceId:device.deviceId inSession:session];
}]];
[alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"device_verification_self_verify_alert_cancel_action", @"Vector", nil)
style:UIAlertActionStyleCancel
handler:nil]];
[self presentViewController:alert animated:YES completion:nil];
self.userNewSignInAlertController = alert;
}
#pragma mark - GDPR consent
@ -4880,8 +5094,6 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
self.gdprConsentNotGivenAlertController = nil;
self.gdprConsentController = nil;
UIViewController *presentingViewController = self.window.rootViewController.presentedViewController ?: self.window.rootViewController;
__weak typeof(self) weakSelf = self;
MXSession *mainSession = self.mxSessions.firstObject;
@ -4901,7 +5113,7 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
if (strongSelf)
{
[strongSelf presentGDPRConsentFromViewController:presentingViewController consentURI:consentURI];
[strongSelf presentGDPRConsentFromViewController:self.presentedViewController consentURI:consentURI];
}
}]];
@ -4909,7 +5121,7 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
style:UIAlertActionStyleCancel
handler:nil]];
[presentingViewController presentViewController:alert animated:YES completion:nil];
[self presentViewController:alert animated:YES completion:nil];
self.gdprConsentNotGivenAlertController = alert;
}
@ -5005,9 +5217,7 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
serviceTermsModalCoordinatorBridgePresenter.delegate = self;
UIViewController *presentingViewController = self.window.rootViewController.presentedViewController ?: self.window.rootViewController;
[serviceTermsModalCoordinatorBridgePresenter presentFrom:presentingViewController animated:YES];
[serviceTermsModalCoordinatorBridgePresenter presentFrom:self.presentedViewController animated:YES];
self.serviceTermsModalCoordinatorBridgePresenter = serviceTermsModalCoordinatorBridgePresenter;
}

View file

@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "camera.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "camera@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "camera@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View file

@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "encryption_normal.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "encryption_normal@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "encryption_normal@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 913 B

View file

@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "encryption_trusted.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "encryption_trusted@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "encryption_trusted@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 804 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "encryption_warning.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "encryption_warning@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "encryption_warning@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 688 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 980 B

View file

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View file

@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "verification_success_shield.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "verification_success_shield@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "verification_success_shield@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

View file

@ -43,7 +43,7 @@
<key>url</key>
<string>https://piwik.riot.im/piwik.php</string>
<key>siteId</key>
<string>1</string>
<string>14</string>
</dict>
<key>showAllEventsInRoomHistory</key>
<false/>

View file

@ -923,3 +923,20 @@
"widget_menu_revoke_permission" = "Премахни достъпа за мен";
"widget_menu_remove" = "Премахни за всички";
"widget_integration_manager_disabled" = "Необходимо е да включите мениджър на интеграции от настройки";
// Accessibility
"accessibility_checkbox_label" = "отметка";
"settings_labs_dm_key_verification" = "Потвърждение на ключ чрез директно съобщение";
"settings_labs_cross_signing" = "Кръстосано-подписване";
"widget_picker_manage_integrations" = "Управление на интеграциите...";
// Room widget permissions
"room_widget_permission_title" = "Зареждане на приспособление";
"room_widget_permission_creator_info_title" = "Приспособлението беше добавено от:";
"room_widget_permission_webview_information_title" = "Използването му може да сложи бисквитки и да сподели данни с %@:\n";
"room_widget_permission_information_title" = "Използването му може да сподели данни с %@:\n";
"room_widget_permission_display_name_permission" = "Вашето име";
"room_widget_permission_avatar_url_permission" = "Адреса на вашата снимка";
"room_widget_permission_user_id_permission" = "Вашето потребителското ID";
"room_widget_permission_theme_permission" = "Вашата тема";
"room_widget_permission_widget_id_permission" = "ID на приспособление";
"room_widget_permission_room_id_permission" = "ID на стая";
"service_terms_modal_policy_checkbox_accessibility_hint" = "Отметнете за да приемете %@";

View file

@ -92,7 +92,7 @@
"auth_reset_password_email_validation_message" = "Mae e-bost wedi'i anfon at %@. Ar ôl i chi ddilyn y ddolen sydd ynddo, cliciwch isod.";
"auth_reset_password_next_step_button" = "Rwyf wedi gwirio fy nghyfeiriad e-bost";
"auth_reset_password_error_unauthorized" = "Methiant gwirio cyfeiriad e-bost: gwnewch yn siŵr eich bod wedi clicio'r ddolen yn yr e-bost";
"auth_reset_password_error_not_found" = "Nid yw'n ymddangos bod eich cyfeiriad e-bost yn gysylltiedig ag Matrix ID ar y hafanweinydd hwn.";
"auth_reset_password_error_not_found" = "Nid yw'n ymddangos bod eich cyfeiriad e-bost yn gysylltiedig ag Dynodwr Matrix ar y hafanweinydd hwn.";
"auth_reset_password_error_is_required" = "Nid oes unrhyw weinydd adnabod wedi'i osod: ychwanegwch un yn opsiynau'r gweinydd i ailosod eich cyfrinair.";
"auth_reset_password_success_message" = "Mae eich cyfrinair wedi'i ailosod.\n\nRydych wedi cael eich allgofnodi o bob dyfais ac ni fyddwch yn derbyn hysbysiadau mwyach. I ail-alluogi hysbysiadau, ail-fewngofnodwch ar bob dyfais.";
"auth_add_email_and_phone_warning" = "Ni chefnogir cofrestru gydag e-bost a rhif ffôn ar yr un pryd nes bod yr api yn bodoli. Dim ond y rhif ffôn fydd yn cael ei ystyried. Gallwch ychwanegu eich e-bost at eich proffil mewn gosodiadau.";
@ -126,7 +126,7 @@
"room_creation_keep_private" = "Cadw'n breifat";
"room_creation_make_private" = "Gwneud yn breifat";
"room_creation_wait_for_creation" = "Mae ystafell eisoes yn cael ei greu. Arhoswch os gwelwch yn dda.";
"room_creation_invite_another_user" = "Chwilio / gwahodd yn ôl ID defnyddiwr, Enw, new e-bost";
"room_creation_invite_another_user" = "Chwilio / gwahodd yn ôl Dynodwr Defnyddiwr, Enw, new e-bost";
"room_creation_error_invite_user_by_email_without_identity_server" = "Nid oes unrhyw weinydd adnabod wedi'i osod felly ni allwch ychwanegu cyfranogwr gydag e-bost.";
// Room recents
"room_recents_directory_section" = "CYFEIRIADUR YSTAFELLOEDD";
@ -158,7 +158,7 @@
"search_people" = "Pobl";
"search_files" = "Ffeiliau";
"search_default_placeholder" = "Chwilio";
"search_people_placeholder" = "Chwilio yn ôl ID defnyddiwr, Enw, new e-bost";
"search_people_placeholder" = "Chwilio yn ôl Dynodwr Defnyddiwr, Enw, new e-bost";
"search_no_result" = "Dim canlyniadau";
"search_in_progress" = "Chwilio…";
// Directory
@ -191,9 +191,9 @@
"room_participants_invite_prompt_title" = "Cadarnhad";
"room_participants_invite_prompt_msg" = "Ydych chi'n siwr eich bod eisau ychwanegu %@ i'r sgwrs?";
"room_participants_filter_room_members" = "Hidlo aelodau'r ystafell";
"room_participants_invite_another_user" = "Chwilio / gwahodd yn ôl ID defnyddiwr, Enw, new e-bost";
"room_participants_invite_another_user" = "Chwilio / gwahodd yn ôl Dynodwr Defnyddiwr, Enw, new e-bost";
"room_participants_invite_malformed_id_title" = "Gwall gwahoddiad";
"room_participants_invite_malformed_id" = "ID camffurfiedig. Dylai fod yn gyfeiriad e-bost neu'n ID Matrix fel '@localpart:domain'";
"room_participants_invite_malformed_id" = "Dynodwr camffurfiedig. Dylai fod yn gyfeiriad e-bost neu'n Ddynodwr Matrix fel '@localpart:domain'";
"room_participants_invited_section" = "GWAHODDWYD";
"room_participants_start_new_chat_error_using_user_email_without_identity_server" = "Nid oes unrhyw weinydd adnabod wedi'i osod felly ni allwch ddechrau sgwrs gyda chyswllt gan ddefnyddio e-bost.";
"room_participants_online" = "Ar-lein";
@ -417,7 +417,7 @@
"settings_add_3pid_password_message" = "I barhau, rhowch eich cyfrinair os gwelwch yn dda";
"settings_add_3pid_invalid_password_message" = "Cyfrinair annilys";
"settings_crypto_device_name" = "Enw Cyhoeddus y Ddyfais: ";
"settings_crypto_device_id" = "\nID y ddyfais: ";
"settings_crypto_device_id" = "\nDynodwr y ddyfais: ";
"settings_crypto_device_key" = "\nAllwedd y ddyfais:\n";
"settings_crypto_export" = "Allfudo allweddi";
"settings_crypto_blacklist_unverified_devices" = "Amgryptio i ddyfeisiau wedi'u gwirio yn unig";
@ -425,14 +425,14 @@
"settings_key_backup_info" = "Sicrheir negeseuon wedi'u hamgryptio gydag amgryptio o'r dechrau i'r diwedd. Dim ond chi a'r derbynnydd / derbynwyr sydd â'r allweddi i ddarllen y negeseuon hyn.";
"settings_key_backup_info_checking" = "Gwirio...";
"settings_key_backup_info_none" = "Nid yw'ch allweddi yn cael eu cadw wrth gefn o'r ddyfais hon.";
"settings_key_backup_info_signout_warning" = "Cysylltwch y ddyfais hon â Allweddi Wrth Gefn cyn arwyddo allan er mwyn osgoi colli unrhyw allweddi a allai fod ar y ddyfais hon yn unig.";
"settings_key_backup_info_signout_warning" = "Cysylltwch y ddyfais hon â Allweddi Wrth Gefn cyn allgofnodi er mwyn osgoi colli unrhyw allweddi a allai fod ar y ddyfais hon yn unig.";
"settings_key_backup_info_version" = "Fersiwn Allweddi Wrth Gefn: %@";
"settings_key_backup_info_algorithm" = "Algorithm: %@";
"settings_key_backup_info_valid" = "Mae'r ddyfais hon yn gwneud copi wrth gefn o'ch allweddi.";
"settings_key_backup_info_not_valid" = "Nid yw'r ddyfais hon yn gwneud copi wrth gefn o'ch allweddi, ond mae gennych gopi wrth gefn y gallwch ei adfer ac ychwanegu ato wrth symud ymlaen.";
"settings_key_backup_info_progress" = "Creu copi wrth gefn o allweddi %@...";
"settings_key_backup_info_progress_done" = "Pob allwedd â copi wrth gefn";
"settings_key_backup_info_trust_signature_unknown" = "Mae gan Allweddi Wrth Gefn lofnod o'r ddyfais gydag ID: %@";
"settings_key_backup_info_trust_signature_unknown" = "Mae gan Allweddi Wrth Gefn lofnod o'r ddyfais gyda dynodwr: %@";
"settings_key_backup_info_trust_signature_valid" = "Mae gan Allweddi Wrth Gefn lofnod dilys o'r ddyfais hon";
"settings_key_backup_info_trust_signature_valid_device_verified" = "Mae gan Allweddi Wrth Gefn lofnod dilys o %@";
"settings_key_backup_info_trust_signature_valid_device_unverified" = "Mae gan Allweddi Wrth Gefn lofnod o %@";
@ -516,12 +516,12 @@
"room_details_addresses_disable_main_address_prompt_title" = "Rhybydd prif gyfeiriad";
"room_details_addresses_disable_main_address_prompt_msg" = "Ni fydd gennych brif gyfeiriad wedi'i nodi. Dewisir ar hap prif gyfeiriad diofyn ar gyfer yr ystafell hon";
"room_details_flair_section" = "Dangos dawn i gymunedau";
"room_details_new_flair_placeholder" = "Ychwanegu ID cymunedol newydd (e.e. +foo%@)";
"room_details_new_flair_placeholder" = "Ychwanegu dynodwr cymunedol newydd (e.e. +foo%@)";
"room_details_flair_invalid_id_prompt_title" = "Fformat annilys";
"room_details_flair_invalid_id_prompt_msg" = "Nid yw %@ yn ddynodwr dilys ar gyfer cymuned";
"room_details_banned_users_section" = "Defnyddwyr gwaharddedig";
"room_details_advanced_section" = "Uwch";
"room_details_advanced_room_id" = "ID Ystafell:";
"room_details_advanced_room_id" = "Dynodwr Ystafell:";
"room_details_advanced_enable_e2e_encryption" = "Galluogi amgryptio (rhybudd: ni ellir ei anablu eto!)";
"room_details_advanced_e2e_encryption_enabled" = "Mae amgryptio wedi'i alluogi yn yr ystafell hon";
"room_details_advanced_e2e_encryption_disabled" = "Nid yw amgryptio wedi'i alluogi yn yr ystafell hon.";
@ -542,7 +542,7 @@
"room_details_save_changes_prompt" = "Hoffech chi gadw'r newidiadau?";
"room_details_set_main_address" = "Gosod fel Prif Gyfeiriad";
"room_details_unset_main_address" = "Dad-osod fel Prif Gyfeiriad";
"room_details_copy_room_id" = "Copio ID Ystafell";
"room_details_copy_room_id" = "Copio Dynodwr Ystafell";
"room_details_copy_room_address" = "Copio Cyfeiriad Ystafell";
"room_details_copy_room_url" = "Copio URL Ystafell";
// Group Details
@ -565,9 +565,9 @@
"group_participants_invite_prompt_title" = "Cadarnhad";
"group_participants_invite_prompt_msg" = "Ydych chi'n siwr eich bod eisau gwahodd %@ i'r grŵp?";
"group_participants_filter_members" = "Hidlo aelodau'r cymuned";
"group_participants_invite_another_user" = "Chwilio / gwahodd yn ôl ID Defnyddiwr neu Enw";
"group_participants_invite_another_user" = "Chwilio / gwahodd yn ôl Dynodwr Defnyddiwr neu Enw";
"group_participants_invite_malformed_id_title" = "Gwall gwahoddiad";
"group_participants_invite_malformed_id" = "ID camffurfiedig. Dylai fod yn ID Matrix fel '@localpart:domain'";
"group_participants_invite_malformed_id" = "Dynodwr camffurfiedig. Dylai fod yn Ddynodwr Matrix fel '@localpart:domain'";
"group_participants_invited_section" = "GWAHODDWYD";
// Group rooms
"group_rooms_filter_rooms" = "Hidlo ystafelloedd y gymuned";
@ -693,7 +693,7 @@
"service_terms_modal_title_identity_server" = "Darganfod Cysylltiadau";
"service_terms_modal_message_identity_server" = "Derbyn telerau'r gweinydd adnabod (%@) i ddarganfod cysylltiadau.";
"deactivate_account_title" = "Dad-actifadu Cyfrif";
"deactivate_account_informations_part1" = "Bydd hyn yn golygu na ellir defnyddio'ch cyfrif yn barhaol. Ni fyddwch yn gallu mewngofnodi, ac ni fydd unrhyw un yn gallu ailgofrestru'r un ID defnyddiwr. Bydd hyn yn achosi i'ch cyfrif adael yr holl ystafelloedd y mae'n cymryd rhan ynddynt, a bydd yn tynnu manylion eich cyfrif o'ch gweinydd adnabod. ";
"deactivate_account_informations_part1" = "Bydd hyn yn golygu na ellir defnyddio'ch cyfrif yn barhaol. Ni fyddwch yn gallu mewngofnodi, ac ni fydd unrhyw un yn gallu ailgofrestru'r un dynodwr defnyddiwr. Bydd hyn yn achosi i'ch cyfrif adael yr holl ystafelloedd y mae'n cymryd rhan ynddynt, a bydd yn tynnu manylion eich cyfrif o'ch gweinydd adnabod. ";
"deactivate_account_informations_part2_emphasize" = "Ni ellir gwrthdroi'r weithred hon.";
"deactivate_account_informations_part3" = "\n\nYn dad-actifadu eich cyfrif ";
"deactivate_account_informations_part4_emphasize" = "nid yw yn ddiofyn yn achosi inni anghofio negeseuon yr ydych wedi'u hanfon. ";
@ -883,3 +883,28 @@
// Generic errors
"error_invite_3pid_with_no_identity_server" = "Ychwanegwch weinydd adnabod yn eich gosodiadau i wahodd trwy e-bost.";
"error_not_supported_on_mobile" = "Ni allwch wneud hyn o %@ ffôn symudol.";
// Accessibility
"accessibility_checkbox_label" = "blwch ticio";
"settings_integrations" = "INTEGREIDDIADAU";
"settings_integrations_allow_button" = "Rheoli integreiddiadau";
"settings_integrations_allow_description" = "Defnyddiwch Reolwr Integreiddio (%@) i reoli bots, pontydd, teclynnau a phecynnau sticeri.\n\nMae Rheolwyr Integreiddio yn derbyn data cyfluniad, a gallant addasu teclynnau, anfon gwahoddiadau ystafell a gosod lefelau pŵer ar eich rhan.";
"settings_labs_dm_key_verification" = "Gwirio allweddi trwy neges uniongyrchol";
"settings_labs_cross_signing" = "Traws-arwyddo";
"widget_menu_refresh" = "Adnewyddu";
"widget_menu_open_outside" = "Agor mewn porwr";
"widget_menu_revoke_permission" = "Dirymu mynediad i mi";
"widget_menu_remove" = "Gwaredu i bawb";
"widget_integration_manager_disabled" = "Mae angen i chi alluogi Rheolwr Integreiddio yn y gosodiadau";
"widget_picker_manage_integrations" = "Rheoli integreiddiadau...";
// Room widget permissions
"room_widget_permission_title" = "Llwytho Teclyn";
"room_widget_permission_creator_info_title" = "Ychwanegwyd y teclyn hwn gan:";
"room_widget_permission_webview_information_title" = "Gall ei ddefnyddio osod cwcis a rhannu data gyda %@:\n";
"room_widget_permission_information_title" = "Gall ei ddefnyddio rhannu data gyda %@:\n";
"room_widget_permission_display_name_permission" = "Eich enw arddangos";
"room_widget_permission_avatar_url_permission" = "Eich URL dangoslun";
"room_widget_permission_user_id_permission" = "Eich dynodwr defnyddiwr";
"room_widget_permission_theme_permission" = "Eich thema";
"room_widget_permission_widget_id_permission" = "Dynodwr Teclyn";
"room_widget_permission_room_id_permission" = "Dynodwr Ystafell";
"service_terms_modal_policy_checkbox_accessibility_hint" = "Ticiwch i dderbyn %@";

View file

@ -54,3 +54,4 @@
"MSG_FROM_USER_IN_ROOM_TITLE" = "%@ in %@";
/* Sticker from a specific person, not referencing a room. */
"STICKER_FROM_USER" = "%@ hat einen Sticker gesendet";
"KEY_VERIFICATION_REQUEST_FROM_USER" = "%@ möchte verifizieren";

View file

@ -904,3 +904,5 @@
"widget_menu_revoke_permission" = "Zugriff für mich widerrufen";
"widget_menu_remove" = "Für alle entfernen";
"widget_integration_manager_disabled" = "Sie müssen den Integration Manager in den Einstellungen aktivieren";
"settings_discovery_settings" = "ERKENNUNG";
"settings_three_pids_management_information_part2" = "Erkennung";

View file

@ -109,3 +109,7 @@
/* Incoming named video conference invite from a specific person */
"VIDEO_CONF_NAMED_FROM_USER" = "Video group call from %@: '%@'";
/** Key verification **/
"KEY_VERIFICATION_REQUEST_FROM_USER" = "%@ wants to verify";

View file

@ -57,6 +57,7 @@
"send_to" = "Send to %@";
"sending" = "Sending";
"close" = "Close";
"skip" = "Skip";
// Accessibility
"accessibility_checkbox_label" = "checkbox";
@ -117,7 +118,7 @@
"auth_reset_password_error_unauthorized" = "Failed to verify email address: make sure you clicked the link in the email";
"auth_reset_password_error_not_found" = "Your email address does not appear to be associated with a Matrix ID on this homeserver.";
"auth_reset_password_error_is_required" = "No identity server is configured: add one in server options to reset your password.";
"auth_reset_password_success_message" = "Your password has been reset.\n\nYou have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, re-log in on each device.";
"auth_reset_password_success_message" = "Your password has been reset.\n\nYou have been logged out of all sessions and will no longer receive push notifications. To re-enable notifications, re-log in on each device.";
"auth_add_email_and_phone_warning" = "Registration with email and phone number at once is not supported yet until the api exists. Only the phone number will be taken into account. You may add your email to your profile in settings.";
"auth_accept_policies" = "Please review and accept the policies of this homeserver:";
"auth_autodiscover_invalid_response" = "Invalid homeserver discovery response";
@ -239,8 +240,9 @@
"room_participants_action_section_admin_tools" = "Admin tools";
"room_participants_action_section_direct_chats" = "Direct chats";
"room_participants_action_section_devices" = "Devices";
"room_participants_action_section_other" = "Other";
"room_participants_action_section_devices" = "Sessions";
"room_participants_action_section_other" = "Options";
"room_participants_action_section_security" = "Security";
"room_participants_action_invite" = "Invite";
"room_participants_action_leave" = "Leave this room";
@ -256,6 +258,22 @@
"room_participants_action_start_voice_call" = "Start voice call";
"room_participants_action_start_video_call" = "Start video call";
"room_participants_action_mention" = "Mention";
"room_participants_action_security_status_verified" = "Verified";
"room_participants_action_security_status_verify" = "Verify";
"room_participants_action_security_status_warning" = "Warning";
"room_participants_action_security_status_loading" = "Loading…";
"room_participants_security_loading" = "Loading…";
"room_participants_security_information_room_not_encrypted" = "Messages in this room are not end-to-end encrypted.";
"room_participants_security_information_room_encrypted" = "Messages in this room are end-to-end encrypted.\n\nYour messages are secured with locks and only you and the recipient have the unique keys to unlock them.";
"room_member_power_level_admin_in" = "Admin in %@";
"room_member_power_level_moderator_in" = "Moderator in %@";
"room_member_power_level_custom_in" = "Custom (%@) in %@";
"room_member_power_level_short_admin" = "Admin";
"room_member_power_level_short_moderator" = "Mod";
"room_member_power_level_short_custom" = "Custom";
// Chat
"room_jump_to_first_unread" = "Jump to first unread message";
@ -275,7 +293,7 @@
"room_message_reply_to_short_placeholder" = "Send a reply…";
"room_offline_notification" = "Connectivity to the server has been lost.";
"room_unsent_messages_notification" = "Messages not sent. %@ or %@ now?";
"room_unsent_messages_unknown_devices_notification" = "Message not sent due to unknown devices being present. %@ or %@ now?";
"room_unsent_messages_unknown_devices_notification" = "Message not sent due to unknown sessions being present. %@ or %@ now?";
"room_ongoing_conference_call" = "Ongoing conference call. Join as %@ or %@.";
"room_ongoing_conference_call_with_close" = "Ongoing conference call. Join as %@ or %@. %@ it.";
"room_ongoing_conference_call_close" = "Close";
@ -341,13 +359,13 @@
"media_type_accessibility_sticker" = "Sticker";
// Unknown devices
"unknown_devices_alert_title" = "Room contains unknown devices";
"unknown_devices_alert" = "This room contains unknown devices which have not been verified.\nThis means there is no guarantee that the devices belong to the users they claim to.\nWe recommend you go through the verification process for each device before continuing, but you can resend the message without verifying if you prefer.";
"unknown_devices_alert_title" = "Room contains unknown sessions";
"unknown_devices_alert" = "This room contains unknown sessions which have not been verified.\nThis means there is no guarantee that the sessions belong to the users they claim to.\nWe recommend you go through the verification process for each session before continuing, but you can resend the message without verifying if you prefer.";
"unknown_devices_send_anyway" = "Send Anyway";
"unknown_devices_call_anyway" = "Call Anyway";
"unknown_devices_answer_anyway" = "Answer Anyway";
"unknown_devices_verify" = "Verify…";
"unknown_devices_title" = "Unknown devices";
"unknown_devices_title" = "Unknown sessions";
// Room Title
"room_title_new_room" = "New room";
@ -389,7 +407,7 @@
"settings_other" = "OTHER";
"settings_labs" = "LABS";
"settings_flair" = "Show flair where allowed";
"settings_devices" = "DEVICES";
"settings_devices" = "SESSIONS";
"settings_cryptography" = "CRYPTOGRAPHY";
"settings_key_backup" = "KEY BACKUP";
"settings_deactivate_account" = "DEACTIVATE ACCOUNT";
@ -416,6 +434,8 @@
"settings_three_pids_management_information_part2" = "Discovery";
"settings_three_pids_management_information_part3" = ".";
"settings_security" = "SECURITY";
"settings_enable_push_notif" = "Notifications on this device";
"settings_show_decrypted_content" = "Show decrypted content";
"settings_global_settings_info" = "Global notification settings are available on your %@ web client";
@ -458,8 +478,6 @@
"settings_labs_room_members_lazy_loading_error_message" = "Your homeserver does not support lazy loading of room members yet. Try later.";
"settings_labs_create_conference_with_jitsi" = "Create conference calls with jitsi";
"settings_labs_message_reaction" = "React to messages with emoji";
"settings_labs_dm_key_verification" = "Key verification by direct message";
"settings_labs_cross_signing" = "Cross-Signing";
"settings_version" = "Version %@";
"settings_olm_version" = "Olm Version %@";
@ -486,27 +504,27 @@
"settings_add_3pid_password_message" = "To continue, please enter your password";
"settings_add_3pid_invalid_password_message" = "Invalid password";
"settings_crypto_device_name" = "Device Public Name: ";
"settings_crypto_device_id" = "\nDevice ID: ";
"settings_crypto_device_key" = "\nDevice key:\n";
"settings_crypto_device_name" = "Session name: ";
"settings_crypto_device_id" = "\nSession ID: ";
"settings_crypto_device_key" = "\nSession key:\n";
"settings_crypto_export" = "Export keys";
"settings_crypto_blacklist_unverified_devices" = "Encrypt to verified devices only";
"settings_crypto_blacklist_unverified_devices" = "Encrypt to verified sessions only";
"settings_deactivate_my_account" = "Deactivate my account";
"settings_key_backup_info" = "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.";
"settings_key_backup_info_checking" = "Checking...";
"settings_key_backup_info_none" = "Your keys are not being backed up from this device.";
"settings_key_backup_info_signout_warning" = "Connect this device to key backup before signing out to avoid losing any keys that may only be on this device.";
"settings_key_backup_info_checking" = "Checking";
"settings_key_backup_info_none" = "Your keys are not being backed up from this session.";
"settings_key_backup_info_signout_warning" = "Connect this session to key backup before signing out to avoid losing any keys that may only be on this device.";
"settings_key_backup_info_version" = "Key Backup Version: %@";
"settings_key_backup_info_algorithm" = "Algorithm: %@";
"settings_key_backup_info_valid" = "This device is backing up your keys.";
"settings_key_backup_info_not_valid" = "This device is not backing up your keys, but you do have an existing backup you can restore from and add to going forward.";
"settings_key_backup_info_progress" = "Backing up %@ keys...";
"settings_key_backup_info_valid" = "This session is backing up your keys.";
"settings_key_backup_info_not_valid" = "This session is not backing up your keys, but you do have an existing backup you can restore from and add to going forward.";
"settings_key_backup_info_progress" = "Backing up %@ keys";
"settings_key_backup_info_progress_done" = "All keys backed up";
"settings_key_backup_info_trust_signature_unknown" = "Backup has a signature from device with ID: %@";
"settings_key_backup_info_trust_signature_valid" = "Backup has a valid signature from this device";
"settings_key_backup_info_trust_signature_unknown" = "Backup has a signature from session with ID: %@";
"settings_key_backup_info_trust_signature_valid" = "Backup has a valid signature from this session";
"settings_key_backup_info_trust_signature_valid_device_verified" = "Backup has a valid signature from %@";
"settings_key_backup_info_trust_signature_valid_device_unverified" = "Backup has a signature from %@";
"settings_key_backup_info_trust_signature_invalid_device_verified" = "Backup has an invalid signature from %@";
@ -515,11 +533,11 @@
"settings_key_backup_button_create" = "Start using Key Backup";
"settings_key_backup_button_restore" = "Restore from Backup";
"settings_key_backup_button_delete" = "Delete Backup";
"settings_key_backup_button_connect" = "Connect this device to Key Backup";
"settings_key_backup_button_connect" = "Connect this session to Key Backup";
"settings_key_backup_delete_confirmation_prompt_title" = "Delete Backup";
"settings_key_backup_delete_confirmation_prompt_msg" = "Are you sure? You will lose your encrypted messages if your keys are not backed up properly.";
"settings_devices_description" = "A device's public name is visible to people you communicate with";
"settings_devices_description" = "A session's public name is visible to people you communicate with";
"settings_discovery_no_identity_server" = "You are not currently using an identity server. To be discoverable by existing contacts you known, add one.";
"settings_discovery_terms_not_signed" = "Agree to the Identity Server (%@) Terms of Service to allow yourself to be discoverable by email address or phone number.";
@ -543,6 +561,33 @@
"settings_identity_server_no_is_description" = "You are not currently using an identity server. To discover and be discoverable by existing contacts you know, add one above.";
// Security settings
"security_settings_title" = "Security";
"security_settings_crypto_sessions" = "MY SESSIONS";
"security_settings_crypto_sessions_loading" = "Loading sessions…";
"security_settings_crypto_sessions_description" = "Trust sessions to grant access to end-to-end encrypted messages. If you dont recognise a session, change your login password and reset your Message Password used for Message Backup.";
"security_settings_backup" = "MESSAGE BACKUP";
"security_settings_crosssigning" = "CROSS-SIGNING";
"security_settings_cryptography" = "CRYPTOGRAPHY";
"security_settings_export_keys_manually" = "Export keys manually";
"security_settings_advanced" = "ADVANCED";
"security_settings_blacklist_unverified_devices" = "Never send messages to untrusted sessions";
"security_settings_blacklist_unverified_devices_description" = "Verify all of a users sessions to mark them as trusted and send messages to them.";
// Manage session
"manage_session_title" = "Manage session";
"manage_session_info" = "SESSION INFO";
"manage_session_name" = "Session name";
"manage_session_trusted" = "Trusted by you";
"manage_session_not_trusted" = "Not trusted";
"manage_session_sign_out" = "Sign out of this session";
// Identity server settings
"identity_server_settings_title" = "Identity Server";
@ -616,7 +661,7 @@
"room_details_advanced_enable_e2e_encryption"="Enable encryption (warning: cannot be disabled again!)";
"room_details_advanced_e2e_encryption_enabled"="Encryption is enabled in this room";
"room_details_advanced_e2e_encryption_disabled"="Encryption is not enabled in this room.";
"room_details_advanced_e2e_encryption_blacklist_unverified_devices"="Encrypt to verified devices only";
"room_details_advanced_e2e_encryption_blacklist_unverified_devices"="Encrypt to verified sessions only";
"room_details_fail_to_update_avatar" = "Fail to update the room photo";
"room_details_fail_to_update_room_name" = "Fail to update the room name";
"room_details_fail_to_update_topic" = "Fail to update the topic";
@ -695,7 +740,7 @@
"event_formatter_jitsi_widget_added" = "VoIP conference added by %@";
"event_formatter_jitsi_widget_removed" = "VoIP conference removed by %@";
"event_formatter_rerequest_keys_part1_link" = "Re-request encryption keys";
"event_formatter_rerequest_keys_part2" = " from your other devices.";
"event_formatter_rerequest_keys_part2" = " from your other sessions.";
"event_formatter_message_edited_mention" = "(edited)";
// Others
@ -718,8 +763,8 @@
// Call
"call_incoming_voice_prompt" = "Incoming voice call from %@";
"call_incoming_video_prompt" = "Incoming video call from %@";
"call_incoming_voice" = "Incoming call...";
"call_incoming_video" = "Incoming video call...";
"call_incoming_voice" = "Incoming call";
"call_incoming_video" = "Incoming video call";
"call_already_displayed" = "There is already a call in progress.";
"call_jitsi_error" = "Failed to join the conference call.";
@ -737,7 +782,7 @@
// Crypto
"e2e_enabling_on_app_update" = "Riot now supports end-to-end encryption but you need to log in again to enable it.\n\nYou can do it now or later from the application settings.";
"e2e_need_log_in_again" = "You need to log back in to generate end-to-end encryption keys for this device and submit the public key to your homeserver.\nThis is a once off; sorry for the inconvenience.";
"e2e_need_log_in_again" = "You need to log back in to generate end-to-end encryption keys for this session and submit the public key to your homeserver.\nThis is a once off; sorry for the inconvenience.";
// Key backup wrong version
"e2e_key_backup_wrong_version_title" = "New Key Backup";
@ -784,7 +829,7 @@
// Widget Picker
"widget_picker_title" = "Integrations";
"widget_picker_manage_integrations" = "Manage integrations...";
"widget_picker_manage_integrations" = "Manage integrations";
// Room widget permissions
"room_widget_permission_title" = "Load Widget";
@ -807,9 +852,9 @@
// Room key request dialog
"e2e_room_key_request_title" = "Encryption key request";
"e2e_room_key_request_message_new_device" = "You added a new device '%@', which is requesting encryption keys.";
"e2e_room_key_request_message" = "Your unverified device '%@' is requesting encryption keys.";
"e2e_room_key_request_start_verification" = "Start verification...";
"e2e_room_key_request_message_new_device" = "You added a new session '%@', which is requesting encryption keys.";
"e2e_room_key_request_message" = "Your unverified session '%@' is requesting encryption keys.";
"e2e_room_key_request_start_verification" = "Start verification";
"e2e_room_key_request_share_without_verifying" = "Share without verifying";
"e2e_room_key_request_ignore_request" = "Ignore request";
@ -854,7 +899,7 @@
// Re-request confirmation dialog
"rerequest_keys_alert_title" = "Request Sent";
"rerequest_keys_alert_message" = "Please launch Riot on another device that can decrypt the message so it can send the keys to this device.";
"rerequest_keys_alert_message" = "Please launch Riot on another device that can decrypt the message so it can send the keys to this session.";
// MARK: Key backup setup
@ -913,6 +958,9 @@
"key_backup_recover_invalid_recovery_key_title" = "Recovery Key Mismatch";
"key_backup_recover_invalid_recovery_key" = "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.";
// Recover from private key
"key_backup_recover_from_private_key_info" = "Restoring backup…";
// Recover from passphrase
"key_backup_recover_from_passphrase_info" = "Use your recovery passphrase to unlock your secure message history";
@ -948,7 +996,7 @@
// Recover
"key_backup_recover_banner_title" = "Never lose encrypted messages";
"key_backup_recover_connent_banner_subtitle" = "Connect this device to Key Backup";
"key_backup_recover_connent_banner_subtitle" = "Connect this session to Key Backup";
// MARK: Sign out warning
@ -969,35 +1017,69 @@
"sign_out_key_backup_in_progress_alert_cancel_action" = "I'll wait";
// MARK: - Device Verification
"device_verification_title" = "Verify device";
"device_verification_title" = "Verify session";
"key_verification_user_title" = "Verify user";
"device_verification_security_advice" = "For maximum security, we recommend you do this in person or use another trusted means of communication";
"device_verification_cancelled" = "The other party cancelled the verification.";
"device_verification_cancelled_by_me" = "The verification has been cancelled. Reason: %@";
"device_verification_error_cannot_load_device" = "Cannot load device information.";
"device_verification_error_cannot_load_device" = "Cannot load session information.";
// Mark: Incoming
"device_verification_incoming_title" = "Incoming Verification Request";
"device_verification_incoming_description_1" = "Verify this device to mark it as trusted. Trusting devices of partners gives you extra peace of mind when using end-to-end encrypted messages.";
"device_verification_incoming_description_2" = "Verifying this device will mark it as trusted, and also mark your device as trusted to the partner.";
"device_verification_incoming_description_1" = "Verify this session to mark it as trusted. Trusting sessions of partners gives you extra peace of mind when using end-to-end encrypted messages.";
"device_verification_incoming_description_2" = "Verifying this session will mark it as trusted, and also mark your session as trusted to the partner.";
// MARK: Start
"device_verification_start_title" = "Verify by comparing a short text string";
"device_verification_start_wait_partner" = "Waiting for partner to accept...";
"device_verification_start_wait_partner" = "Waiting for partner to accept";
"device_verification_start_use_legacy" = "Nothing appearing? Not all clients supports interactive verification yet. Use legacy verification.";
"device_verification_start_verify_button" = "Begin Verifying";
"device_verification_start_use_legacy_action" = "Use Legacy Verification";
// MARK: Self verification start
"device_verification_self_verify_alert_title" = "New Sign In";
"device_verification_self_verify_alert_message" = "Use this session to verify your new one, granting it access to encrypted messages: %@\nIf you didnt sign in to this session, your account may be compromised.";
"device_verification_self_verify_alert_cancel_action" = "This wasn't me";
"device_verification_self_verify_start_verify_action" = "Start verification";
"device_verification_self_verify_start_information" = "Use this session to verify your new one, granting it access to encrypted messages.";
"device_verification_self_verify_start_waiting" = "Waiting…";
// MARK: Self verification wait
"device_verification_self_verify_wait_title" = "Complete security";
"device_verification_self_verify_wait_information" = "Use an existing session to verify this new one, granting it access to encrypted messages.";
"device_verification_self_verify_wait_waiting" = "Waiting…";
// MARK: Verify
"device_verification_verify_title_emoji" = "Verify this device by confirming the following emoji appear on the screen of the partner";
"device_verification_verify_title_number" = "Verify this device by confirming the following numbers appear on the screen of the partner";
"device_verification_verify_wait_partner" = "Waiting for partner to confirm...";
// Device
"device_verification_verify_title_emoji" = "Verify this session by confirming the following emoji appear on the screen of the partner";
"device_verification_verify_title_number" = "Verify this session by confirming the following numbers appear on the screen of the partner";
"device_verification_verify_wait_partner" = "Waiting for partner to confirm…";
// User
"key_verification_verify_user_title_emoji" = "Verify this user by confirming the following unique emoji appears on their screen, in the same order.";
"key_verification_verify_user_title_number" = "Verify this user by confirming the following numbers appear on their screen, in the same order.";
// MARK: Verified
// Device
"device_verification_verified_title" = "Verified!";
"device_verification_verified_description_1" = "You've successfully verified this device.";
"device_verification_verified_description_1" = "You've successfully verified this session.";
"device_verification_verified_description_2" = "Secure messages with this user are end-to-end encrypted and not able to be read by third parties.";
"device_verification_verified_got_it_button" = "Got it";
// User
"key_verification_verified_user_description_1" = "Youve successfully verified this user.";
"key_verification_verified_user_description_2" = "Messages with this user in this room are end-to-end encrypted and cant be read by third parties.";
// MARK: Emoji
"device_verification_emoji_dog" = "Dog";
"device_verification_emoji_cat" = "Cat";
@ -1087,3 +1169,92 @@
// Generic errors
"error_invite_3pid_with_no_identity_server" = "Add an identity server in your settings to invite by email.";
"error_not_supported_on_mobile" = "You can't do this from %@ mobile.";
// MARK: - Key Verification
"key_verification_bootstrap_not_setup_title" = "Error";
"key_verification_bootstrap_not_setup_message" = "You have to bootstrap cross-signing";
// Tiles
"key_verification_tile_request_incoming_title" = "Verification request";
"key_verification_tile_request_outgoing_title" = "Verification sent";
"key_verification_tile_request_status_data_loading" = "Data loading…";
"key_verification_tile_request_status_waiting" = "Waiting…";
"key_verification_tile_request_status_expired" = "Expired";
"key_verification_tile_request_status_cancelled_by_me" = "You cancelled";
"key_verification_tile_request_status_cancelled" = "%@ cancelled";
"key_verification_tile_request_status_accepted" = "You accepted";
"key_verification_tile_request_incoming_approval_accept" = "Accept";
"key_verification_tile_request_incoming_approval_decline" = "Decline";
"key_verification_tile_conclusion_done_title" = "Verified";
"key_verification_tile_conclusion_warning_title" = "Unstrusted sign in";
// Incoming key verification request
"key_verification_incoming_request_incoming_alert_message" = "%@ wants to verify";
// MARK: QR code
"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_scan_code_action" = "Scan their code";
"key_verification_verify_qr_code_cannot_scan_action" = "Can't scan?";
"key_verification_verify_qr_code_other_scan_my_code_title" = "Did the other user successfully scan the QR code?";
"key_verification_verify_qr_code_scan_other_code_success_title" = "Code validated!";
"key_verification_verify_qr_code_scan_other_code_success_message" = "QR code has been successfully validated.";
// MARK: Scan confirmation
// Scanning
"key_verification_scan_confirmation_scanning_title" = "Almost there! Waiting for confirmation…";
"key_verification_scan_confirmation_scanning_user_waiting_other" = "Waiting for %@…";
"key_verification_scan_confirmation_scanning_device_waiting_other" = "Waiting for other device…";
// Scanned
"key_verification_scan_confirmation_scanned_title" = "Almost there!";
"key_verification_scan_confirmation_scanned_user_information" = "Is %@ showing the same shield?";
"key_verification_scan_confirmation_scanned_device_information" = "Is the other device showing the same shield?";
// MARK: - User verification
// Start
"user_verification_start_verify_action" = "Start verification";
"user_verification_start_information_part1" = "For extra security, verify ";
"user_verification_start_information_part2" = " by checking a one-time code on both your devices.";
"user_verification_start_waiting_partner" = "Waiting for %@…";
"user_verification_start_additional_information" = "To be secure, do this in person or use another way to communicate.";
// Sessions list
"user_verification_sessions_list_user_trust_level_trusted_title" = "Trusted";
"user_verification_sessions_list_user_trust_level_warning_title" = "Warning";
"user_verification_sessions_list_user_trust_level_unknown_title" = "Unknown";
"user_verification_sessions_list_information" = "Messages with this user in this room are end-to-end encrypted and cant be read by third parties.";
"user_verification_sessions_list_table_title" = "Sessions";
"user_verification_sessions_list_session_trusted" = "Trusted";
"user_verification_sessions_list_session_untrusted" = "Not trusted";
// Session details
"user_verification_session_details_trusted_title" = "Trusted";
"user_verification_session_details_untrusted_title" = "Warning";
"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 ";
"user_verification_session_details_information_trusted_other_user_part2" = " verified it:";
"user_verification_session_details_information_untrusted_current_user" = "Verify this session to mark it as trusted & grant it access to encrypted messages:";
"user_verification_session_details_information_untrusted_other_user" = " signed in using a new session:";
"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_other_user" = "Manually verify";

View file

@ -54,3 +54,4 @@
"MSG_FROM_USER_IN_ROOM_TITLE" = "%@ erabiltzailea %@ gelan";
/* Sticker from a specific person, not referencing a room. */
"STICKER_FROM_USER" = "%@ erabiltzaileak eranskailu bat bidali du";
"KEY_VERIFICATION_REQUEST_FROM_USER" = "%@(e)k egiaztatu nahi du";

View file

@ -68,7 +68,7 @@
"auth_missing_phone" = "Telefono zenbakia falta da";
"auth_missing_email_or_phone" = "E-mail helbidea edo telefono zenbakia falta da";
"auth_password_dont_match" = "Pasahitzak ez datoz bat";
"auth_forgot_password" = "Pasahitza ahaztu duzu?";
"auth_forgot_password" = "Pasahitza ahaztuta?";
"auth_use_server_options" = "Erabili zerbitzari pertsonalizatuaren ezarpenak (aurreratua)";
"auth_email_validation_message" = "Egiaztatu zure e-mail helbidea erregistroarekin jarraitzeko";
"auth_recaptcha_message" = "Hasiera-zerbitzari honek robot bat ez zarela egiaztatu nahi du";
@ -924,3 +924,29 @@
"room_widget_permission_widget_id_permission" = "Trepetaren ID-a";
"room_widget_permission_room_id_permission" = "Gelaren ID-a";
"widget_picker_manage_integrations" = "Integrazioak kudeatu...";
// Accessibility
"accessibility_checkbox_label" = "egiaztaketa-koadroa";
"settings_labs_dm_key_verification" = "Gako egiaztaketa mezu zuzenaren bidez";
"settings_labs_cross_signing" = "Zeharkako sinadura";
"service_terms_modal_policy_checkbox_accessibility_hint" = "Markatu %@ onartzeko";
"key_verification_tile_request_incoming_title" = "Egiaztaketa eskaria";
"key_verification_tile_request_outgoing_title" = "Egiaztaketa bidalita";
"key_verification_tile_request_status_data_loading" = "Datuak kargatzen…";
"key_verification_tile_request_status_waiting" = "Itxaroten…";
"key_verification_tile_request_status_expired" = "Iraungita";
"key_verification_tile_request_status_cancelled_by_me" = "Utzi duzu";
"key_verification_tile_request_status_cancelled" = "%@(e)k utzita";
"key_verification_tile_request_status_accepted" = "Onartu duzu";
"key_verification_tile_request_incoming_approval_accept" = "Onartu";
"key_verification_tile_request_incoming_approval_decline" = "Ukatu";
"key_verification_tile_conclusion_done_title" = "Egiaztatuta";
"key_verification_tile_conclusion_warning_title" = "Fidagarritasun gabeko saio hasiera";
"key_verification_incoming_request_incoming_alert_message" = "%@(e)k egiaztatu nahi du";
"settings_security" = "SEGURTASUNA";
"settings_labs_enable_cross_signing" = "Gaitu zeharkako sinatzea erabiltzaileko egiaztatzeko eta ez saioko (garapenean)";
// Security settings
"security_settings_title" = "Segurtasuna";
"security_settings_crypto_sessions" = "NIRE SAIOAK";
"security_settings_backup" = "MEZUEN BABES-KOPIA";
"security_settings_advanced" = "AURRERATUA";
"security_settings_blacklist_unverified_devices" = "Ez bidali inoiz mezuak egiaztatu gabeko saioetara";

View file

@ -54,3 +54,4 @@
"MSG_FROM_USER_IN_ROOM_TITLE" = "%@ dans %@";
/* Sticker from a specific person, not referencing a room. */
"STICKER_FROM_USER" = "%@ a envoyé un sticker";
"KEY_VERIFICATION_REQUEST_FROM_USER" = "%@ veut vérifier";

View file

@ -169,7 +169,7 @@
"room_participants_action_section_admin_tools" = "Outils d'administration";
"room_participants_action_section_direct_chats" = "Discussions directes";
"room_participants_action_section_devices" = "Appareils";
"room_participants_action_section_other" = "Autres";
"room_participants_action_section_other" = "Options";
"room_participants_action_invite" = "Inviter";
"room_participants_action_leave" = "Quitter ce salon";
"room_participants_action_remove" = "Exclure de ce salon";
@ -944,3 +944,69 @@
"service_terms_modal_policy_checkbox_accessibility_hint" = "Cochez pour accepter %@";
"settings_labs_dm_key_verification" = "Vérification de clé par message direct";
"settings_labs_cross_signing" = "Signature croisée";
"key_verification_tile_request_incoming_title" = "Demande de vérification";
"key_verification_tile_request_outgoing_title" = "Vérification envoyée";
"key_verification_tile_request_status_data_loading" = "Chargement des données…";
"key_verification_tile_request_status_waiting" = "En attente…";
"key_verification_tile_request_status_expired" = "Expiré";
"key_verification_tile_request_status_cancelled_by_me" = "Vous avez annulé";
"key_verification_tile_request_status_cancelled" = "%@ a annulé";
"key_verification_tile_request_status_accepted" = "Vous avez accepté";
"key_verification_tile_request_incoming_approval_accept" = "Accepter";
"key_verification_tile_request_incoming_approval_decline" = "Refuser";
"key_verification_tile_conclusion_done_title" = "Vérifié";
"key_verification_tile_conclusion_warning_title" = "Connexion non approuvée";
"key_verification_incoming_request_incoming_alert_message" = "%@ veut vérifier";
"settings_labs_enable_cross_signing" = "Activer la vérification croisée pour vérifier par utilisateurs plutôt que par appareil (en développement)";
"settings_security" = "SÉCURITÉ";
// Security settings
"security_settings_title" = "Sécurité";
"security_settings_crypto_sessions" = "MES SESSIONS";
"security_settings_crypto_sessions_description" = "Faites confiance à des sessions pour leur accorder laccès aux messages chiffrés de bout en bout. Si vous ne reconnaissez pas une session, modifiez votre mot de passe de connexion et réinitialisez votre mot de passe de messages utilisé pour la sauvegarde des messages.";
"security_settings_backup" = "SAUVEGARDE DES MESSAGES";
"security_settings_advanced" = "AVANCÉ";
"security_settings_blacklist_unverified_devices" = "Ne jamais envoyer de message aux sessions non fiables";
"security_settings_blacklist_unverified_devices_description" = "Vérifier toutes les sessions dun utilisateur pour les marquer comme fiables et leur envoyer des messages.";
"security_settings_export_keys_manually" = "Exporter les clés manuellement";
// Manage session
"manage_session_title" = "Gérer la session";
"manage_session_info" = "INFORMATIONS DE LA SESSION";
"manage_session_name" = "Nom de lappareil";
"manage_session_trusted" = "Vous lui faites confiance";
"manage_session_not_trusted" = "Vous ne lui faites pas confiance";
"manage_session_sign_out" = "Se déconnecter de cet appareil";
"room_participants_action_section_security" = "Sécurité";
"room_participants_action_security_status_verified" = "Vérifié";
"room_participants_action_security_status_verify" = "Vérifier";
"room_participants_action_security_status_warning" = "Attention";
"room_participants_security_loading" = "Chargement…";
"room_participants_security_information_room_not_encrypted" = "Les messages de ce salon ne sont pas chiffrés de bout en bout.";
"room_participants_security_information_room_encrypted" = "Les messages de ce salon sont chiffrés de bout en bout.\n\nVos messages sont sécurisés avec des verrous et seuls vous et le destinataire avez les clés uniques pour les déverrouiller.";
"key_verification_user_title" = "Vérifier lutilisateur";
"key_verification_verify_user_title_emoji" = "Vérifiez cet utilisateur en confirmant que les émojis uniques suivants apparaissent sur son écran, dans le même ordre.";
"key_verification_verify_user_title_number" = "Vérifiez cet utilisateur en confirmant que les nombres suivants apparaissent sur son écran, dans le même ordre.";
"key_verification_verified_user_description_1" = "Vous avez vérifié cet utilisateur.";
"key_verification_verified_user_description_2" = "Les messages avec cet utilisateur dans ce salon sont chiffrés de bout en bout et ne peuvent être lus par des tiers.";
"user_verification_start_verify_action" = "Commencer la vérification";
"user_verification_start_information_part1" = "Pour une meilleur sécurité, vérifiez ";
"user_verification_start_information_part2" = " en comparant un code à usage unique sur vos deux appareils.";
"user_verification_start_waiting_partner" = "Nous attendons %@…";
"user_verification_start_additional_information" = "Pour une meilleure sécurité, faites cela en personne ou utilisez un autre moyen de communication.";
"user_verification_sessions_list_user_trust_level_trusted_title" = "Fiable";
"user_verification_sessions_list_user_trust_level_warning_title" = "Attention";
"user_verification_sessions_list_user_trust_level_unknown_title" = "Inconnu";
"user_verification_sessions_list_information" = "Les messages avec cet utilisateur dans ce salon sont chiffrés de bout en bout et ne peuvent pas être lus par des tiers.";
"user_verification_sessions_list_table_title" = "Sessions";
"user_verification_sessions_list_session_trusted" = "Fiable";
"user_verification_sessions_list_session_untrusted" = "Non fiable";
"user_verification_session_details_trusted_title" = "Fiable";
"user_verification_session_details_untrusted_title" = "Attention";
"user_verification_session_details_information_trusted_current_user" = "Cette session est fiable pour la messagerie sécurisée car vous lavez vérifiée :";
"user_verification_session_details_information_trusted_other_user_part1" = "Cet appareil est fiable pour la messagerie sécurisée car ";
"user_verification_session_details_information_trusted_other_user_part2" = " la vérifié :";
"user_verification_session_details_information_untrusted_current_user" = "Vérifiez cette session pour la marquer comme fiable et lui permettre daccéder aux messages sécurisés :";
"user_verification_session_details_information_untrusted_other_user" = " sest connecté en utilisant un nouvel appareil :";
"user_verification_session_details_additional_information_untrusted_other_user" = "Tant que cet utilisateur ne fera pas confiance à cet appareil, les messages envoyés par et vers lui seront marqués par des avertissements. Sinon, vous pouvez le vérifier manuellement.";
"user_verification_session_details_additional_information_untrusted_current_user" = "Si vous ne vous êtes pas connecté à cette session, votre compte est peut-être compromis.";
"user_verification_session_details_verify_action_current_user" = "Vérifier";
"user_verification_session_details_verify_action_other_user" = "Vérifier manuellement";

View file

@ -54,3 +54,4 @@
"MSG_FROM_USER_IN_ROOM_TITLE" = "%@ in %@ -ban/ben";
/* Sticker from a specific person, not referencing a room. */
"STICKER_FROM_USER" = "%@ matricát küldött";
"KEY_VERIFICATION_REQUEST_FROM_USER" = "%@ ellenőrizni szeretné";

View file

@ -13,7 +13,7 @@
"leave" = "Elhagyás";
"remove" = "Eltávolítás";
"invite" = "Meghívás";
"retry" = "Újrapróbál";
"retry" = "Újra";
"cancel" = "Mégse";
"save" = "Ment";
// Room Details
@ -180,7 +180,7 @@
"room_participants_action_section_admin_tools" = "Adminisztrátori eszközök";
"room_participants_action_section_direct_chats" = "Közvetlen csevegések";
"room_participants_action_section_devices" = "Eszközök";
"room_participants_action_section_other" = "Egyéb";
"room_participants_action_section_other" = "Opciók";
"room_participants_action_invite" = "Meghívó";
"room_participants_action_leave" = "Szoba elhagyása";
"room_participants_action_remove" = "Eltávolítás a szobából";
@ -946,3 +946,69 @@
"service_terms_modal_policy_checkbox_accessibility_hint" = "Az engedélyezéshez jelöld be: %@";
"settings_labs_dm_key_verification" = "Kulcs ellenőrzés közvetlen üzenetben";
"settings_labs_cross_signing" = "Kereszt-aláírás";
"key_verification_tile_request_incoming_title" = "Ellenőrzési kérés";
"key_verification_tile_request_outgoing_title" = "Ellenőrzés kérése elküldve";
"key_verification_tile_request_status_data_loading" = "Adat betöltés…";
"key_verification_tile_request_status_waiting" = "Várakozik…";
"key_verification_tile_request_status_expired" = "Lejárt";
"key_verification_tile_request_status_cancelled_by_me" = "Megszakítottad";
"key_verification_tile_request_status_cancelled" = "%@ megszakította";
"key_verification_tile_request_status_accepted" = "Elfogadtad";
"key_verification_tile_request_incoming_approval_accept" = "Elfogad";
"key_verification_tile_request_incoming_approval_decline" = "Elutasít";
"key_verification_tile_conclusion_done_title" = "Hitelesített";
"key_verification_tile_conclusion_warning_title" = "Megbízhatatlan belépés";
"key_verification_incoming_request_incoming_alert_message" = "%@ ellenőrizni szeretné";
"settings_labs_enable_cross_signing" = "Kereszt-aláírás engedélyezése a felhasználó alapú azonosításhoz az eszköz alapú helyett (fejlesztés alatt)";
"settings_security" = "BIZTONSÁG";
// Security settings
"security_settings_title" = "Biztonság";
"security_settings_crypto_sessions" = "MUNKAMENETEIM";
"security_settings_crypto_sessions_description" = "Bízz meg a munkamenetbe a végpontok között titkosított üzenetek hozzáféréséhez. Ha nem ismered fel a munkamenetet, változtasd meg a bejelentkezési jelszavad és az Üzenet Mentéshez használt jelszavad.";
"security_settings_backup" = "ÜZENET MENTÉS";
"security_settings_advanced" = "HALADÓ";
"security_settings_blacklist_unverified_devices" = "Soha ne küldj üzenetet megbízhatatlan munkamenetekbe";
"security_settings_blacklist_unverified_devices_description" = "Ellenőrizd minden felhasználó minden munkamenetét, hogy megbízhatónak tudd jelölni azokat és üzenet küldhess nekik.";
"security_settings_export_keys_manually" = "Kulcsok kimentése kézzel";
// Manage session
"manage_session_title" = "Munkamenet kezelése";
"manage_session_info" = "MUNKAMENET INFORMÁCIÓ";
"manage_session_name" = "Eszköznév";
"manage_session_trusted" = "Szerinted megbízható";
"manage_session_not_trusted" = "Megbízhatatlan";
"manage_session_sign_out" = "Kijelentkezés erről az eszközről";
"room_participants_action_section_security" = "Biztonság";
"room_participants_action_security_status_verified" = "Hitelesített";
"room_participants_action_security_status_verify" = "Ellenőriz";
"room_participants_action_security_status_warning" = "Figyelmeztetés";
"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_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.";
"key_verification_verified_user_description_2" = "Az üzenetek ezzel a felhasználóval végponttól végpontig titkosítva vannak és más nem tudja elolvasni.";
"user_verification_start_verify_action" = "Ellenőrzés elindítása";
"user_verification_start_information_part1" = "A nagyobb biztonság érdekében ellenőrizd. ";
"user_verification_start_information_part2" = " az egyszeri kóddal mindkét eszközön.";
"user_verification_start_waiting_partner" = "Várakozás erre: %@…";
"user_verification_start_additional_information" = "A biztonság érdekében ezt végezd el személyesen vagy egy megbízható kommunikációs csatornán.";
"user_verification_sessions_list_user_trust_level_trusted_title" = "Megbízható";
"user_verification_sessions_list_user_trust_level_warning_title" = "Figyelmeztetés";
"user_verification_sessions_list_user_trust_level_unknown_title" = "Ismeretlen";
"user_verification_sessions_list_information" = "Az üzenetek ezzel a felhasználóval végponttól végpontig titkosítva vannak és más nem tudja elolvasni.";
"user_verification_sessions_list_table_title" = "Munkamenetek";
"user_verification_sessions_list_session_trusted" = "Megbízható";
"user_verification_sessions_list_session_untrusted" = "Megbízhatatlan";
"user_verification_session_details_trusted_title" = "Megbízható";
"user_verification_session_details_untrusted_title" = "Figyelmeztetés";
"user_verification_session_details_information_trusted_current_user" = "Ez a munkamenet megbízhatónak van jelölve a biztonságos üzenetküldéshez, mert ellenőrizted:";
"user_verification_session_details_information_trusted_other_user_part1" = "Ez az eszköz megbízhatónak van jelölve a biztonságos üzenetküldéshez, mert ";
"user_verification_session_details_information_trusted_other_user_part2" = " ellenőrizve:";
"user_verification_session_details_information_untrusted_current_user" = "A munkamenet megbízhatónak való jelöléséhez és a titkosított üzenetekhez való hozzáférés engedélyezéséhez hitelesítsd azt:";
"user_verification_session_details_information_untrusted_other_user" = " új eszközzel bejelentkezve:";
"user_verification_session_details_additional_information_untrusted_other_user" = "Amíg a felhasználó nem jelöli megbízhatónak ezt az eszközt addig az eszközről küldött és az eszközre érkező üzenetek figyelmeztetéssel lesznek ellátva. Vagy te is ellenőrizheted az eszközt.";
"user_verification_session_details_additional_information_untrusted_current_user" = "Ha nem te jelentkeztél be ebbe a munkamenetbe akkor a fiókodat feltörték.";
"user_verification_session_details_verify_action_current_user" = "Ellenőriz";
"user_verification_session_details_verify_action_other_user" = "Manuális ellenőrzés";

View file

@ -1,5 +1,5 @@
/* New message from a specific person, not referencing a room */
"MSG_FROM_USER" = "Messaggio ricevuto da %@";
"MSG_FROM_USER" = "%@ ha inviato un messaggio";
/* New message from a specific person in a named room */
"MSG_FROM_USER_IN_ROOM" = "%@ ha scritto in %@";
/* New message from a specific person, not referencing a room. Content included. */
@ -11,7 +11,7 @@
/* New action message from a specific person in a named room. */
"ACTION_FROM_USER_IN_ROOM" = "%@: * %@ %@";
/* New action message from a specific person, not referencing a room. */
"IMAGE_FROM_USER" = "%@ ha inviato un'immagine %@";
"IMAGE_FROM_USER" = "%@ ha invitato un'immagine %@";
/* New action message from a specific person in a named room. */
"IMAGE_FROM_USER_IN_ROOM" = "%@ ha inviato un'immagine %@ in %@";
/* A single unread message in a room */
@ -50,3 +50,8 @@
"VOICE_CONF_NAMED_FROM_USER" = "Chiamata di gruppo da %@: '%@'";
/* Incoming named video conference invite from a specific person */
"VIDEO_CONF_NAMED_FROM_USER" = "Video chiamata di gruppo da %@: '%@'";
/* Message title for a specific person in a named room */
"MSG_FROM_USER_IN_ROOM_TITLE" = "%@ in %@";
/* Sticker from a specific person, not referencing a room. */
"STICKER_FROM_USER" = "%@ ha inviato un adesivo";
"KEY_VERIFICATION_REQUEST_FROM_USER" = "%@ vuole verificare";

View file

@ -1,7 +1,7 @@
// Titles
"title_home" = "Home";
"title_favourites" = "Preferiti";
"title_people" = "Persone";
"title_people" = "Chat dirette";
"title_rooms" = "Stanze";
"store_full_description" = "Comunica, a modo tuo.\n\nUn'app di messaggistica, sotto il tuo controllo e interamente flessibile. Riot ti permette di comunicare a modo tuo. Creata per [matrix] - lo standard per le comunicazioni aperte, decentralizzate.\n\nOttieni un account matrix.org gratuito, ottieni il tuo server su https://modular.im, o usa un altro server Matrix.\n\nPerché scegliere Riot.im?\n\n• COMUNICAZIONE COMPLETA: crea stanze per i tuoi team, i tuoi amici, la tua comunità - come preferisci! Chatta, condividi file, aggiungi widget e fai videochiamate vocali - tutto gratuito.\n\n• GRANDI INTEGRAZIONI: usa Riot.im con gli strumenti che conosci ed ami. Con Riot.im puoi addirittura chattare con utenti e gruppi su altre applicazioni di messaggistica.\n\n• PRIVATO E SICURO: tieni segrete le tue conversazioni. Una crittografia end-to-end allo stato dell'arte assicura che le comunicazioni private restino tali.\n\n• APERTO, NON CHIUSO: open source e costruito su Matrix. Possiedi i tuoi dati ospitando il tuo server personale, o scegliendone uno di cui ti fidi.\n\n• OVUNQUE TU SIA: resta in contatto ovunque tu sia con la cronologia dei messaggi totalmente sincronizzata tra i tuoi dispositivi ed online su https://riot.im.";
"title_groups" = "Comunità";
@ -12,12 +12,12 @@
"invite" = "Invita";
"cancel" = "Annulla";
"save" = "Salva";
"join" = "Unisciti";
"join" = "Entra";
"decline" = "Rifiuta";
"accept" = "Accetto";
"preview" = "Anteprima";
"rename" = "Rinomina";
"collapse" = "collassa";
"collapse" = "riduci";
"send_to" = "Invia a %@";
// Authentication
"auth_login" = "Accedi";
@ -33,7 +33,7 @@
"auth_email_placeholder" = "Indirizzo email";
"auth_optional_phone_placeholder" = "Numero di telefono (opzionale)";
"auth_phone_placeholder" = "Numero di telefono";
"auth_repeat_password_placeholder" = "Ripeti password";
"auth_repeat_password_placeholder" = "Ripeti la password";
"auth_repeat_new_password_placeholder" = "Conferma la nuova password";
"auth_home_server_placeholder" = "URL (es. https://matrix.org)";
"auth_identity_server_placeholder" = "URL (es. https://vector.im)";
@ -55,9 +55,9 @@
"auth_forgot_password" = "Password dimenticata?";
"auth_email_validation_message" = "Per favore controlla la tua email per proseguire la registrazione";
"auth_msisdn_validation_title" = "In attesa di verifica";
"auth_msisdn_validation_message" = "Un SMS è stato spedito con il codice di attivazione. Per favore inserisci il codice qui sotto.";
"auth_msisdn_validation_message" = "Ti è stato spedito un SMS con il codice di attivazione. Per favore inserisci il codice qui sotto.";
"auth_msisdn_validation_error" = "Impossibile verificare il numero di telefono.";
"auth_reset_password_message" = "Per ripristinare la password, inserisci l'indirizzo email associato al tuo account:";
"auth_reset_password_message" = "Per ripristinare la password inserisci l'indirizzo email associato al tuo account:";
// String for App Store
"store_short_description" = "Conversazioni sicure e decentralizzate";
// Actions
@ -67,33 +67,33 @@
"create" = "Crea";
"start" = "Inizia";
"retry" = "Riprova";
"on" = "Attivo";
"off" = "Disattivo";
"on" = "On";
"off" = "Off";
"camera" = "Fotocamera";
"voice" = "Voce";
"voice" = "Audio";
"video" = "Video";
"active_call" = "Chiamata attiva";
"active_call_details" = "Chiamata attiva (%@)";
"active_call" = "Chiamata in corso";
"active_call_details" = "Chiamata in corso (%@)";
"later" = "Più avanti";
"sending" = "Inviando";
"auth_submit" = "Invia";
"auth_login_single_sign_on" = "Accedi con single sign-on";
"auth_untrusted_id_server" = "Il server identità non è affidabile";
"auth_untrusted_id_server" = "L'affidabilità dell'Identity Server non è stata accertata";
"auth_password_dont_match" = "Le password non corrispondono";
"auth_username_in_use" = "Nome utente in uso";
"auth_email_not_found" = "Invio dell'email fallito: Questo indirizzo email non è stato trovato";
"auth_use_server_options" = "Usa opzioni server personalizzate (avanzate)";
"auth_recaptcha_message" = "Questo server home vorrebbe assicurarsi che tu non sia un robot";
"auth_reset_password_missing_email" = "L'indirizzo email associato al tuo account deve essere inserito.";
"auth_reset_password_missing_password" = "Una nuova password deve essere inserita.";
"auth_reset_password_email_validation_message" = "Un'email è stata inviata a %s. Appena avrai seguito il link lì contenuto, clicca qui sotto.";
"auth_use_server_options" = "Usa le opzioni personalizzate del Server (avanzate)";
"auth_recaptcha_message" = "Questo Home Server vuol esser certo che tu non sia un robot";
"auth_reset_password_missing_email" = "Va inserito l'indirizzo email associato al tuo account.";
"auth_reset_password_missing_password" = "Va inserita una nuova password.";
"auth_reset_password_email_validation_message" = "Un'email è stata inviata a %s. Dopo aver cliccato il link che contiene, clicca qui sotto.";
"auth_reset_password_next_step_button" = "Ho verificato il mio indirizzo email";
"auth_reset_password_error_unauthorized" = "Verifica indirizzo email fallita: assicurati di aver cliccato sul link contenuto nell'email";
"auth_reset_password_error_not_found" = "Il tuo indirizzo email non sembra associato a nessun ID Matrix su questo server home.";
"auth_reset_password_success_message" = "La tua password è stata ripristinata.\n\n Sei stato disconnesso da tutti i dispositivi e non riceverai più alcuna notifica. Per riabilitare le notifiche, riconnettiti su ciascun dispositivo.";
"auth_add_email_and_phone_warning" = "La registrazione con email e numero di telefono in una volta sola non è ancora supportata (relative API in sviluppo). Sarà utilizzato solo il numero di telefono. Puoi aggiungere la tua email al tuo profilo dalle impostazioni.";
"auth_accept_policies" = "Per favore, rivedere e accettare le politiche di questo server home:";
"auth_autodiscover_invalid_response" = "Risposta alla scoperta di un homeserver non valida";
"auth_reset_password_error_not_found" = "Il tuo indirizzo email non sembra associato a nessun ID utente registrato su questo Home Server.";
"auth_reset_password_success_message" = "La tua password è stata ripristinata.\n\nSei stato disconnesso da tutti i dispositivi e non riceverai più alcuna notifica. Per riabilitare le notifiche, riconnettiti su ciascun dispositivo.";
"auth_add_email_and_phone_warning" = "Al momento non è ancora possibile registrarsi contemporaneamente con indirizzo email e numero di telefono e quindi verrà utilizzato solo il numero di telefono. Puoi aggiungere la tua email al tuo profilo dall menù Impostazioni.";
"auth_accept_policies" = "Per favore, rileggi e accetta i termini di servizio di questo Home Server:";
"auth_autodiscover_invalid_response" = "Risposta Home Server non valida";
// Chat creation
"room_creation_title" = "Nuova chat";
"room_creation_account" = "Account";
@ -108,13 +108,13 @@
"room_creation_make_public_prompt_msg" = "Sei sicuro di voler rendere pubblica questa chat? Chiunque potrà leggere i tuoi messaggi e unirsi alla chat.";
"room_creation_keep_private" = "Mantieni privata";
"room_creation_make_private" = "Rendi privata";
"room_creation_wait_for_creation" = "Una stanza sta già venendo creata. Per favore attendi.";
"room_creation_wait_for_creation" = "Una stanza è già in fase di creazione. Per favore attendi.";
"room_creation_invite_another_user" = "Cerca / invita per ID utente, nome o email";
// Room recents
"room_recents_directory_section" = "ELENCO STANZE";
"room_recents_directory_section_network" = "Rete";
"room_recents_favourites_section" = "PREFERITI";
"room_recents_people_section" = "PERSONE";
"room_recents_people_section" = "CHAT DIRETTE";
"room_recents_conversations_section" = "STANZE";
"room_recents_no_conversation" = "Nessuna stanza";
"room_recents_low_priority_section" = "BASSA PRIORITÀ";
@ -124,7 +124,7 @@
"room_recents_create_empty_room" = "Crea stanza";
"room_recents_join_room" = "Entra nella stanza";
"room_recents_join_room_title" = "Entra in una stanza";
"room_recents_join_room_prompt" = "Digita ID o soprannome (alias)";
"room_recents_join_room_prompt" = "Digita ID stanza o il suo nome";
// People tab
"people_invites_section" = "INVITI";
"people_conversation_section" = "CONVERSAZIONI";
@ -144,19 +144,19 @@
"search_no_result" = "Nessun risultato";
"search_in_progress" = "Ricerca…";
// Directory
"directory_cell_title" = "Esplora elenco";
"directory_cell_title" = "Esplora l'elenco";
"directory_cell_description" = "%tu stanze";
"directory_search_results_title" = "Esplora risultati elenco";
"directory_search_results" = "%tu risultati trovati per %@";
"directory_search_results_more_than" = ">%tu risultati trovati per %@";
"directory_searching_title" = "Ricerca negli elenchi…";
"directory_search_fail" = "Fallita la ricerca di informazioni";
"directory_search_fail" = "La ricerca di informazioni è fallita";
// Contacts
"contacts_address_book_section" = "CONTATTI LOCALI";
"contacts_address_book_matrix_users_toggle" = "Solo utenti Matrix";
"contacts_address_book_no_contact" = "Nessun contatto locale";
"contacts_address_book_permission_required" = "Permesso richiesto per accedere ai contatti";
"contacts_address_book_permission_denied" = "Non hai permesso a Riot di accedere ai tuoi contatti";
"contacts_address_book_permission_required" = "Riot deve essere autorizzato per poter accedere alla Rubrica locale";
"contacts_address_book_permission_denied" = "Non hai autorizzato Riot ad accedere alla Rubrica locale";
"contacts_user_directory_section" = "ELENCO UTENTI";
"contacts_user_directory_offline_section" = "ELENCO UTENTI (offline)";
// Chat participants
@ -164,17 +164,17 @@
"room_participants_add_participant" = "Aggiungi membro";
"room_participants_one_participant" = "1 membro";
"room_participants_multi_participants" = "%d membri";
"room_participants_leave_prompt_title" = "Lascia stanza";
"room_participants_leave_prompt_title" = "Esci dalla stanza";
"room_participants_leave_prompt_msg" = "Sei sicuro di voler uscire dalla stanza?";
"room_participants_remove_prompt_title" = "Conferma";
"room_participants_remove_prompt_msg" = "Sei sicuro di voler rimuovere %@ da questa chat?";
"room_participants_remove_third_party_invite_msg" = "Finché non esistono le API, la rimozione di inviti di terze parti non è possibile";
"room_participants_invite_prompt_title" = "Conferma";
"room_participants_invite_prompt_msg" = "Sei sicuro di voler invitare %@ in questa chat?";
"room_participants_filter_room_members" = "Filtra i membri della stanza";
"room_participants_filter_room_members" = "Cerca tra i membri della stanza";
"room_participants_invite_another_user" = "Cerca / invita per ID utente, nome o email";
"room_participants_invite_malformed_id_title" = "Errore durante l'invito";
"room_participants_invite_malformed_id" = "ID incorretto. Dovrebbe essere un indirizzo email o un ID Matrix come '@localpart:domain'";
"room_participants_invite_malformed_id" = "ID incorretto. Dovrebbe essere un indirizzo email o un ID utente tipo '@localpart:domain'";
"room_participants_invited_section" = "INVITATI";
"room_participants_online" = "Online";
"room_participants_offline" = "Offline";
@ -182,23 +182,23 @@
"room_participants_idle" = "Inattivo";
"room_participants_now" = "adesso";
"room_participants_ago" = "fa";
"room_participants_action_section_admin_tools" = "Strumenti admin";
"room_participants_action_section_admin_tools" = "Strumenti Admin";
"room_participants_action_section_direct_chats" = "Chat dirette";
"room_participants_action_section_devices" = "Dispositivi";
"room_participants_action_section_other" = "Altro";
"room_participants_action_section_other" = "Opzioni";
"room_participants_action_invite" = "Invita";
"room_participants_action_leave" = "Lascia questa stanza";
"room_participants_action_leave" = "Esci da questa stanza";
"room_participants_action_remove" = "Rimuovi da questa stanza";
"room_participants_action_ban" = "Bandisci da questa stanza";
"room_participants_action_unban" = "Togli il bando";
"room_participants_action_ban" = "Banna da questa stanza";
"room_participants_action_unban" = "Rimuovi il ban";
"room_participants_action_ignore" = "Nascondi tutti i messaggi di questo utente";
"room_participants_action_unignore" = "Mostra tutti i messaggi di questo utente";
"room_participants_action_set_default_power_level" = "Ripristina ad utente normale";
"room_participants_action_set_moderator" = "Rendi moderatore";
"room_participants_action_set_admin" = "Rendi amministratore";
"room_participants_action_set_moderator" = "Nomina moderatore";
"room_participants_action_set_admin" = "Nomina amministratore";
"room_participants_action_start_new_chat" = "Inizia nuova chat";
"room_participants_action_start_voice_call" = "Avvia chiamata vocale";
"room_participants_action_start_video_call" = "Avvia videochiamata";
"room_participants_action_start_voice_call" = "Avvia chiamata audio";
"room_participants_action_start_video_call" = "Avvia chiamata video";
"room_participants_action_mention" = "Citazione";
// Chat
"room_jump_to_first_unread" = "Vai al primo messaggio non letto";
@ -207,62 +207,62 @@
"room_one_user_is_typing" = "%@ sta scrivendo…";
"room_two_users_are_typing" = "%@ e %@ stanno scrivendo…";
"room_many_users_are_typing" = "%@, %@ e altri stanno scrivendo…";
"room_message_placeholder" = "Invia un messaggio (non criptato)…";
"room_message_reply_to_placeholder" = "Invia una risposta (non criptata)…";
"room_message_placeholder" = "Invia un messaggio (non cifrato)…";
"room_message_reply_to_placeholder" = "Invia una risposta (non cifrata)…";
"room_message_unable_open_link_error_message" = "Impossibile aprire il link.";
"room_do_not_have_permission_to_post" = "Non hai il permesso di pubblicare in questa stanza";
"encrypted_room_message_placeholder" = "Invia un messaggio criptato…";
"encrypted_room_message_reply_to_placeholder" = "Invia una risposta criptata…";
"encrypted_room_message_placeholder" = "Invia un messaggio cifrato…";
"encrypted_room_message_reply_to_placeholder" = "Invia una risposta cifrata…";
"room_message_short_placeholder" = "Invia un messaggio…";
"room_message_reply_to_short_placeholder" = "Invia una risposta…";
"room_offline_notification" = "La connessione al server è stata persa.";
"room_unsent_messages_notification" = "Messaggi non inviati. %1$s o %2$s ora?";
"room_unsent_messages_unknown_devices_notification" = "Messaggi non inviati a causa di dispositivi sconosciuti qui presenti. %1$s o %2$s ora?";
"room_ongoing_conference_call" = "Chiamata di conferenza in corso. Unisciti come %@ o %@.";
"room_ongoing_conference_call_with_close" = "Chiamata di conferenza in corso. Unisciti come %@ o %@. %@.";
"room_unsent_messages_unknown_devices_notification" = "Messaggi non inviati a causa della presenza di dispositivi sconosciuti. %1$s o %2$s ora?";
"room_ongoing_conference_call" = "Avvio conferenza. Unisciti come %@ o %@.";
"room_ongoing_conference_call_with_close" = "Avvio conferenza. Unisciti come %@ o %@. %@.";
"room_ongoing_conference_call_close" = "Chiudi";
"room_conference_call_no_power" = "Hai bisogno dei permessi per gestire le chiamate di gruppo in questa stanza";
"room_prompt_resend" = "Rinvia tutto";
"room_conference_call_no_power" = "Non hai permessi sufficienti per avviare una conferenza in questa stanza";
"room_prompt_resend" = "Reinvia tutto";
"room_prompt_cancel" = "annulla tutto";
"room_resend_unsent_messages" = "Reinvia i messaggi non spediti";
"room_delete_unsent_messages" = "Elimina messaggi non spediti";
"room_delete_unsent_messages" = "Elimina i messaggi non spediti";
"room_event_action_copy" = "Copia";
"room_event_action_quote" = "Cita";
"room_event_action_redact" = "Rimuovi";
"room_event_action_more" = "Altro";
"room_event_action_share" = "Condividi";
"room_event_action_permalink" = "Collegamento permanente";
"room_event_action_view_source" = "Vedi sorgente";
"room_event_action_view_decrypted_source" = "Vedi sorgente decriptata";
"room_event_action_report" = "Segnala contenuto";
"room_event_action_permalink" = "Permalink";
"room_event_action_view_source" = "Vedi il codice sorgente";
"room_event_action_view_decrypted_source" = "Vedi il codice sorgente decifrato";
"room_event_action_report" = "Segnala il contenuto";
"room_event_action_report_prompt_reason" = "Motivo della segnalazione";
"room_event_action_kick_prompt_reason" = "Motivo per cui rimuovi questo utente";
"room_event_action_ban_prompt_reason" = "Motivo per cui banni questo utente";
"room_event_action_report_prompt_ignore_user" = "Vuoi nascondere tutti i messaggi da questo utente?";
"room_event_action_report_prompt_ignore_user" = "Vuoi nascondere tutti i messaggi di questo utente?";
"room_event_action_save" = "Salva";
"room_event_action_resend" = "Reinvia";
"room_event_action_delete" = "Elimina";
"room_event_action_cancel_send" = "Annulla invio";
"room_event_action_cancel_download" = "Annulla download";
"room_event_action_view_encryption" = "Informazioni crittografia";
"room_warning_about_encryption" = "La crittografia da-utente-a-utente è in fase sperimentale e potrebbe non esser ancora affidabile.\n\nNon dovesti ancora farci affidamento per proteggere i tuoi dati.\n\nI dispositivi non potranno decrittare la cronologia dei messaggi precedenti all'entrata nella stanza.\n\nI messaggi crittografati non saranno visibili dalle applicazioni che non hanno ancora implementato la crittografia.";
"room_event_action_view_encryption" = "Informazioni sulla crittografia";
"room_warning_about_encryption" = "La crittografia E2E è in fase sperimentale e potrebbe non esser ancora affidabile.\n\nNon dovesti ancora farci affidamento per proteggere i tuoi dati.\n\nI dispositivi non potranno decifrare i messaggi precedenti alla tua entrata nella stanza.\n\nI messaggi cifrati non saranno visibili dalle applicazioni per Matrix che non hanno ancora implementato la crittografia.";
"room_event_failed_to_send" = "Invio fallito";
"room_action_send_photo_or_video" = "Invia foto o video";
"room_action_send_sticker" = "Invia sticker";
"room_replacement_information" = "Questa stanza è stata sostituita e non è più attiva.";
"room_replacement_information" = "Questa stanza è stata sostituita da un'altra e non è più attiva.";
"room_replacement_link" = "La conversazione continua qui.";
"room_predecessor_information" = "Questa stanza è la continuazione di un'altra conversazione.";
"room_predecessor_link" = "Clicca per vedere messaggi più vecchi.";
"room_predecessor_information" = "Questa stanza contiene una conversazione cominciata altrove.";
"room_predecessor_link" = "Clicca per vedere i messaggi più vecchi.";
"room_resource_limit_exceeded_message_contact_1" = " Per favore ";
"room_resource_limit_exceeded_message_contact_2_link" = "contatta l'amministratore del servizio";
"room_resource_limit_exceeded_message_contact_3" = " per continuare ad usare questo servizio.";
"room_resource_usage_limit_reached_message_1_default" = "Questo server home ha superato uno dei limiti delle risorse, pertanto ";
"room_resource_usage_limit_reached_message_1_monthly_active_user" = "Questo server home ha raggiunto il limite mensile di utenti attivi, pertanto ";
"room_resource_usage_limit_reached_message_1_default" = "Questo Home Server ha superato uno dei limiti delle risorse, pertanto ";
"room_resource_usage_limit_reached_message_1_monthly_active_user" = "Questo Home Server ha raggiunto il limite mensile di utenti attivi, pertanto ";
"room_resource_usage_limit_reached_message_2" = "alcuni utenti non potranno accedere.";
"room_resource_usage_limit_reached_message_contact_3" = " per aumentare questo limite.";
// Unknown devices
"unknown_devices_alert_title" = "La stanza contiene dispositivi sconosciuti";
"unknown_devices_alert" = "Questa stanza contiene dispositivi sconosciuti che non sono stati verificati.\nCiò significa che non esiste alcuna garanzia che i dispositivi siano davvero quelli di chi dice di possederli.\nPrima di continuare si consiglia di effettuare la verifica di ogni dispositivo, ma se vuoi è comunque possibile rispedire il messaggio senza fare alcuna verifica.";
"unknown_devices_alert" = "Questa stanza contiene dispositivi sconosciuti che non sono stati verificati.\nNon v'è alcuna garanzia che le persone che utilizzano quei dispositivi siano davvero chi dicono d'essere.\nSi consiglia di verificare ogni dispositivo prima di continuare, ma se si preferisce, è comunque possibile inviare ugualmente il messaggio anche senza la verifica.";
"unknown_devices_send_anyway" = "Invia comunque";
"unknown_devices_call_anyway" = "Chiama comunque";
"unknown_devices_answer_anyway" = "Rispondi comunque";
@ -276,20 +276,20 @@
"room_title_members" = "%@ membri";
"room_title_one_member" = "1 membro";
// Room Preview
"room_preview_invitation_format" = "Sei stato invitato ad unirti in questa stanza da %@";
"room_preview_subtitle" = "Questa è l'anteprima della stanza. Le interazioni con la stanza sono disabilitate.";
"room_preview_unlinked_email_warning" = "Questo invito è stato spedito da %@, che non è associato a questo account. È possibile che tu voglia connetterti con un altro account o aggiungere questo indirizzo email al tuo account.";
"room_preview_try_join_an_unknown_room" = "Stai provando ad accedere a %@. Desideri entrare per partecipare alla discussione?";
"room_preview_invitation_format" = "Sei stato invitato ad entrare in questa stanza da %@";
"room_preview_subtitle" = "Questa è l'anteprima della stanza. Le interazioni sono disabilitate.";
"room_preview_unlinked_email_warning" = "Questo invito è stato spedito a %@, che non è associato a questo account. Puoi aggiungere questa email al tuo account o provare ad accedere con un account differente.";
"room_preview_try_join_an_unknown_room" = "Stai provando ad accedere a %s. Desideri entrare per partecipare alla discussione?";
"room_preview_try_join_an_unknown_room_default" = "una stanza";
// Settings
"settings_title" = "Impostazioni";
"account_logout_all" = "Sconnetti tutti gli account";
"settings_config_no_build_info" = "Nessuna informazione di build";
"account_logout_all" = "Disconnetti tutti gli account";
"settings_config_no_build_info" = "Nessuna informazione su questa versione";
"settings_mark_all_as_read" = "Segna tutti i messaggi come letti";
"settings_report_bug" = "Segnala errore";
"settings_clear_cache" = "Elimina cache";
"settings_config_home_server" = "L'Homeserver è %@";
"settings_config_identity_server" = "L'Identity server è %@";
"settings_config_home_server" = "L'Home Server è %@";
"settings_config_identity_server" = "L'Identity Server è %@";
"settings_config_user_id" = "Connesso come %@";
"settings_user_settings" = "IMPOSTAZIONI UTENTE";
"settings_notifications_settings" = "IMPOSTAZIONI NOTIFICHE";
@ -300,14 +300,14 @@
"settings_advanced" = "AVANZATE";
"settings_other" = "ALTRO";
"settings_labs" = "LABORATORIO";
"settings_flair" = "Mostra predisposizione se permesso";
"settings_flair" = "Mostra la predisposizione quando è consentito";
"settings_devices" = "DISPOSITIVI";
"settings_cryptography" = "CRITTOGRAFIA";
"settings_key_backup" = "BACKUP DELLE CHIAVI";
"settings_deactivate_account" = "DISATTIVA ACCOUNT";
"settings_sign_out" = "Disconnetti";
"settings_sign_out_confirmation" = "Sei sicuro?";
"settings_sign_out_e2e_warn" = "Perderai le tue chiavi di crittografia da-utente-a-utente. Questo significa che non potrai più leggere i vecchi messaggi nelle stanze crittografate su questo dispositivo.";
"settings_sign_out_e2e_warn" = "Perderai le tue chiavi crittografiche E2E. Questo significa che non potrai più leggere i vecchi messaggi nelle stanze cifrate su questo dispositivo.";
"settings_profile_picture" = "Immagine profilo";
"settings_display_name" = "Nome visualizzato";
"settings_first_name" = "Nome";
@ -324,13 +324,13 @@
"settings_night_mode" = "Modalità notte";
"settings_fail_to_update_profile" = "Errore nell'aggiornamento del profilo";
"settings_enable_push_notif" = "Notifiche per questo dispositivo";
"settings_show_decrypted_content" = "Mostra contenuto decrittato";
"settings_global_settings_info" = "Le impostazioni globali di notifica sono disponibili nel tuo %@ web client";
"settings_show_decrypted_content" = "Mostra il contenuto decifrato";
"settings_global_settings_info" = "Le impostazioni di notifica avanzate sono disponibili nel tuo %@ web client";
"settings_pin_rooms_with_missed_notif" = "Segna le stanze con notifiche perse";
"settings_pin_rooms_with_unread" = "Segna le stanze con messaggi non letti";
"settings_on_denied_notification" = "Le notifiche non sono permesse per %@, abilitale nelle impostazioni del tuo dispositivo";
"settings_enable_callkit" = "Chiamate integrate";
"settings_callkit_info" = "Ricevi le chiamate in arrivo nel blocca schermo. Mostra le chiamate Riot nella cronologia di chiamate del dispositivo. Se iCloud è attivo, questa cronologia sarà condivisa con Apple.";
"settings_callkit_info" = "Ricevi le chiamate in arrivo sul blocca schermo. Mostra le chiamate Riot nella cronologia di chiamate del dispositivo. Se iCloud è attivo, questa cronologia sarà condivisa con Apple.";
"settings_ui_language" = "Lingua";
"settings_ui_theme" = "Tema";
"settings_ui_theme_auto" = "Automatico";
@ -341,12 +341,12 @@
"settings_ui_theme_picker_message" = "\"Automatico\" usa l'impostazione \"Inverti Colori\" del tuo dispositivo";
"settings_unignore_user" = "Mostrare tutti i messaggi da %@?";
"settings_contacts_discover_matrix_users" = "Usa email e numeri di telefono per trovare utenti";
"settings_contacts_phonebook_country" = "Nazione rubrica telefonica";
"settings_labs_e2e_encryption" = "Crittografia da-utente-a-utente";
"settings_contacts_phonebook_country" = "Prefisso telefonico internazionale";
"settings_labs_e2e_encryption" = "Crittografia E2E";
"settings_labs_e2e_encryption_prompt_message" = "Per finire la configurazione della crittografia devi rieseguire l'accesso.";
"settings_labs_room_members_lazy_loading" = "Caricamento posticipato dei membri della stanza";
"settings_labs_room_members_lazy_loading_error_message" = "Il tuo Homeserver non supporta ancora il caricamento intelligente dei membri delle stanze. Prova in seguito.";
"settings_labs_create_conference_with_jitsi" = "Crea una videoconferenza con jitsi";
"settings_labs_room_members_lazy_loading" = "Caricamento differito dei membri della stanza";
"settings_labs_room_members_lazy_loading_error_message" = "Il tuo Home Server non supporta ancora il caricamento differito dei membri delle stanze. Prova più avanti.";
"settings_labs_create_conference_with_jitsi" = "Avvia una conferenza usando Jitsi";
"settings_version" = "Versione %@";
"settings_olm_version" = "Versione Olm %@";
"settings_copyright" = "Copyright";
@ -357,41 +357,41 @@
"settings_privacy_policy_url" = "https://riot.im/privacy";
"settings_third_party_notices" = "Avvisi di terze parti";
"settings_send_crash_report" = "Invia dati di utilizzo anonimi";
"settings_enable_rageshake" = "Agita con rabbia per segnalare un errore";
"settings_enable_rageshake" = "Per segnalare un errore agita il dispositivo con rabbia";
"settings_old_password" = "vecchia password";
"settings_new_password" = "nuova password";
"settings_confirm_password" = "conferma password";
"settings_fail_to_update_password" = "Aggiornamento password fallito";
"settings_password_updated" = "La tua password è stata aggiornata";
"settings_crypto_device_name" = "Nome pubblico dispositivo: ";
"settings_crypto_device_id" = "\nID Dispositivo: ";
"settings_crypto_device_id" = "\nID dispositivo: ";
"settings_crypto_device_key" = "\nChiave dispositivo:\n";
"settings_crypto_export" = "Esporta chiavi";
"settings_crypto_blacklist_unverified_devices" = "Crittografa solo per i dispositivi verificati";
"settings_crypto_blacklist_unverified_devices" = "Cifratura solo per i dispositivi verificati";
"settings_deactivate_my_account" = "Disattiva il mio account";
"settings_key_backup_info" = "I messaggi crittografati sono protetti con la crittografia da-utente-a-utente. Solo tu e il/i destinatario/i avete le chiavi per leggere questi messaggi.";
"settings_key_backup_info" = "I messaggi nelle stanze cifrate sono protetti con crittografia E2E. Solo tu e il/i destinatario/i avete le chiavi crittografiche per leggere questi messaggi.";
"settings_key_backup_info_checking" = "Verifica...";
"settings_key_backup_info_none" = "Nessun Backup programmato per le Chiavi da questo dispositivo.";
"settings_key_backup_info_signout_warning" = "Connetti questo dispositivo al backup chiavi prima di disconnetterti per evitare di perdere eventuali chiavi presenti solo qui.";
"settings_key_backup_info_none" = "Questo dispositivo non sta facendo il Backup delle chiavi.";
"settings_key_backup_info_signout_warning" = "Prima di disconnetterti effettua un Backup delle chiavi per evitare di perdere eventuali chiavi presenti solo questo dispositivo.";
"settings_key_backup_info_version" = "Versione backup chiave: %@";
"settings_key_backup_info_algorithm" = "Algoritmo: %@";
"settings_key_backup_info_valid" = "Questo dispositivo sta eseguendo il backup delle tue chiavi.";
"settings_key_backup_info_not_valid" = "Questo dispositivo non sta eseguendo il Backup delle tue Chiavi, ma é disponibile un vecchio Backup da cui puoi ripristinarle.";
"settings_key_backup_info_valid" = "Questo dispositivo sta eseguendo il Backup delle tue chiavi.";
"settings_key_backup_info_not_valid" = "Questo dispositivo non sta eseguendo il Backup delle tue Chiavi. Però è disponibile un vecchio Backup da cui puoi ripristinarle.";
"settings_key_backup_info_progress" = "Backup di %@ chiavi…";
"settings_key_backup_info_progress_done" = "Backup di tutte le chiavi completato";
"settings_key_backup_info_trust_signature_unknown" = "Il backup ha una firma dal dispositivo con ID: %@";
"settings_key_backup_info_trust_signature_unknown" = "Il Backup ha una firma dal dispositivo con ID: %@";
"settings_key_backup_info_trust_signature_valid" = "Il backup ha una firma valida da questo dispositivo";
"settings_key_backup_info_trust_signature_valid_device_verified" = "Il backup ha una firma valida da %@";
"settings_key_backup_info_trust_signature_valid_device_unverified" = "Il backup ha una firma da %@";
"settings_key_backup_info_trust_signature_invalid_device_verified" = "Il backup ha una firma non valida da %@";
"settings_key_backup_info_trust_signature_invalid_device_unverified" = "Il backup ha una firma non valida da %@";
"settings_key_backup_button_create" = "Inizia ad usare il backup chiavi";
"settings_key_backup_button_restore" = "Ripristina da backup";
"settings_key_backup_info_trust_signature_valid_device_verified" = "Il Backup ha una firma valida da %@";
"settings_key_backup_info_trust_signature_valid_device_unverified" = "Il Backup ha una firma da %@";
"settings_key_backup_info_trust_signature_invalid_device_verified" = "Il Backup ha una firma non valida da %@";
"settings_key_backup_info_trust_signature_invalid_device_unverified" = "Il Backup ha una firma non valida da %@";
"settings_key_backup_button_create" = "Inizia ad usare il Backup delle chiavi";
"settings_key_backup_button_restore" = "Ripristina da Backup";
"settings_key_backup_button_delete" = "Elimina backup";
"settings_key_backup_delete_confirmation_prompt_title" = "Elimina backup";
"settings_key_backup_delete_confirmation_prompt_msg" = "Sei sicuro? Se non hai eseguito un Backup delle Chiavi perderai i tuoi messaggi crittografati.";
"settings_key_backup_delete_confirmation_prompt_title" = "Elimina Backup";
"settings_key_backup_delete_confirmation_prompt_msg" = "Sei sicuro? Se non hai eseguito un Backup delle chiavi perderai i tuoi messaggi cifrati.";
// Room Details
"room_details_title" = "Dettagli canale";
"room_details_title" = "Dettagli stanza";
"room_details_people" = "Membri";
"room_details_files" = "File";
"room_details_settings" = "Impostazioni";
@ -407,8 +407,8 @@
"room_details_access_section_anyone_apart_from_guest" = "Chiunque conosca il link della stanza, eccetto gli ospiti";
"room_details_access_section_anyone" = "Chiunque conosca il link della stanza, compresi gli ospiti";
"room_details_access_section_no_address_warning" = "Per poter essere linkata, la stanza deve avere un indirizzo";
"room_details_access_section_directory_toggle" = "Mostra questa stanza nell'elenco delle stanze";
"room_details_history_section" = "Chi può leggere la cronologia?";
"room_details_access_section_directory_toggle" = "Mostra questa stanza nell'elenco delle stanze pubbliche";
"room_details_history_section" = "Chi può leggere la Timeline?";
"room_details_history_section_anyone" = "Chiunque";
"room_details_history_section_members_only" = "Solo i membri (dal momento in cui questa opzione è stata selezionata)";
"room_details_history_section_members_only_since_invited" = "Solo i membri (dal momento in cui vengono invitati)";
@ -593,13 +593,13 @@
"key_backup_setup_skip_alert_title" = "Sei sicuro?";
"key_backup_setup_skip_alert_message" = "Se ti disconnetti oppure perdi il dispositivo potresti perdere i tuoi messaggi crittografati.";
"key_backup_setup_skip_alert_skip_action" = "Salta";
"key_backup_setup_intro_title" = "Non perdere mai i messaggi crittografati";
"key_backup_setup_intro_info" = "I messaggi nelle stanze crittografate sono protetti con crittografia da-utente-a-utente. Solo tu e il/i destinatario/i avete le chiavi per leggere questi messaggi. \n \nFai un backup delle tue chiavi per evitare di perderle.";
"key_backup_setup_intro_title" = "Non perdere mai i messaggi cifrati";
"key_backup_setup_intro_info" = "I messaggi nelle stanze cifrate sono protetti con crittografia E2E. Solo tu e il/i destinatario/i avete le chiavi per leggere questi messaggi. \n \nFai un backup delle tue chiavi crittografiche per evitare di perderle.";
"key_backup_setup_intro_setup_action_without_existing_backup" = "Inizia ad usare il backup chiavi";
"key_backup_setup_intro_manual_export_info" = "(Avanzato)";
"key_backup_setup_intro_manual_export_action" = "Esporta manualmente le chiavi";
"key_backup_setup_passphrase_title" = "Proteggi il tuo backup con una frase d'accesso";
"key_backup_setup_passphrase_info" = "Salveremo una copia crittografata delle tue chiavi nel tuo Homeserver. Proteggi il tuo backup con una frase di sicurezza per tenerlo sicuro. \n \nPer una massima sicurezza, dovrebbe essere diversa dalla password del tuo account.";
"key_backup_setup_passphrase_info" = "Sul tuo Home Server verrà effettuato un Backup cifrato delle tue chiavi crittograficher. Proteggi il Backup con una password perchè sia al sicuro.\n \nPer una massima sicurezza, la password del Backup dovrebbe essere diversa dalla password del tuo account.";
"key_backup_setup_passphrase_passphrase_title" = "Inserisci";
"key_backup_setup_passphrase_passphrase_placeholder" = "Inserisci frase d'accesso";
"key_backup_setup_passphrase_passphrase_valid" = "Bene!";
@ -613,7 +613,7 @@
"key_backup_setup_passphrase_setup_recovery_key_action" = "(Avanzato) Imposta con chiave di ripristino";
"key_backup_setup_success_title" = "Completato!";
// Success from passphrase
"key_backup_setup_success_from_passphrase_info" = "Backup delle tue chiavi in corso.\n\nLa tua chiave di ripristino è uno strumento di sicurezza - puoi usarla per recuperare l'accesso ai tuoi messaggi crittografati se dimentichi la tua frase d'accesso. \n\nTieni la tua chiave di ripristino in un luogo sicuro, come un password manager (o una cassaforte).";
"key_backup_setup_success_from_passphrase_info" = "Backup delle tue chiavi in corso.\n\nIl tuo codice di recupero è un'ancora di salvezza - puoi usarlo per riaccedere ai tuoi messaggi cifrati se dimentichi la password. \n\nSalva il tuo codice di recupero in un luogo sicuro, tipo un password manager (o una cassaforte).";
"key_backup_setup_success_from_passphrase_save_recovery_key_action" = "Salva chiave di ripristino";
"key_backup_setup_success_from_passphrase_done_action" = "Fatto";
// Success from recovery key
@ -642,34 +642,34 @@
"key_backup_recover_done_action" = "Fatto";
"key_backup_setup_banner_title" = "Non perdere mai i messaggi crittografati";
"key_backup_setup_banner_subtitle" = "Inizia ad usare il backup chiavi";
"key_backup_recover_banner_title" = "Non perdere mai i messaggi crittografati";
"key_backup_recover_banner_title" = "Non perdere mai i messaggi cifrati";
"sign_out_existing_key_backup_alert_title" = "Sei sicuro di volerti disconnettere?";
"sign_out_existing_key_backup_alert_sign_out_action" = "Disconnetti";
"sign_out_non_existing_key_backup_alert_title" = "Se ti disconnetti ora, perderai l'accesso ai tuoi messaggi crittografati";
"sign_out_non_existing_key_backup_alert_title" = "Se adesso ti disconnetti, perderai l'accesso ai tuoi messaggi cifrati";
"sign_out_non_existing_key_backup_alert_setup_key_backup_action" = "Inizia ad usare il Backup delle chiavi";
"sign_out_non_existing_key_backup_alert_discard_key_backup_action" = "Non voglio i miei messaggi crittografati";
"sign_out_non_existing_key_backup_sign_out_confirmation_alert_title" = "Perderai i tuoi messaggi crittografati";
"sign_out_non_existing_key_backup_sign_out_confirmation_alert_message" = "Perderai l'accesso ai tuoi messaggi crittografati a meno che non fai il Backup delle tue chiavi prima di disconnetterti.";
"sign_out_non_existing_key_backup_alert_discard_key_backup_action" = "Non voglio i miei messaggi cifrati";
"sign_out_non_existing_key_backup_sign_out_confirmation_alert_title" = "Perderai i tuoi messaggi cifrati";
"sign_out_non_existing_key_backup_sign_out_confirmation_alert_message" = "Perderai l'accesso ai tuoi messaggi cifrati a meno che tu faccia il Backup delle chiavi prima di disconnetterti.";
"sign_out_non_existing_key_backup_sign_out_confirmation_alert_sign_out_action" = "Disconnetti";
"sign_out_non_existing_key_backup_sign_out_confirmation_alert_backup_action" = "Backup";
"sign_out_key_backup_in_progress_alert_title" = "Backup chiavi in corso. Se ti disconnetti ora, perderai l'accesso ai tuoi messaggi crittografati.";
"sign_out_key_backup_in_progress_alert_discard_key_backup_action" = "Non voglio i miei messaggi crittografati";
"sign_out_key_backup_in_progress_alert_title" = "Backup delle chiavi in corso. Se ti disconnetti ora, perderai l'accesso ai tuoi messaggi cifrati.";
"sign_out_key_backup_in_progress_alert_discard_key_backup_action" = "Non voglio i miei messaggi cifrati";
"sign_out_key_backup_in_progress_alert_cancel_action" = "Attendo";
"close" = "Chiudi";
"auth_forgot_password_error_no_configured_identity_server" = "Nessun identità server è configurata: aggiungine uno per reimpostare la password.";
"auth_forgot_password_error_no_configured_identity_server" = "Non è stato configurato alcun Identity: aggiungine uno per poter reimpostare la password.";
"auth_softlogout_signed_out" = "Sei uscito";
"auth_softlogout_sign_in" = "Accedi";
"auth_softlogout_reason" = "L'amministratore homeserver (%1$@) ti ha disconnesso dal tuo account %2$@ (%3$@).";
"auth_softlogout_recover_encryption_keys" = "Accedi per recuperare le chiavi di crittografia archiviate esclusivamente su questo dispositivo. Ti servono per leggere tutti i tuoi messaggi sicuri su qualsiasi dispositivo.";
"auth_softlogout_clear_data" = "Cancella dati personali";
"auth_softlogout_clear_data_message_1" = "Avviso: i tuoi dati personali (comprese le chiavi di crittografia) sono ancora memorizzati su questo dispositivo.";
"auth_softlogout_clear_data_message_2" = "Cancellalo se hai finito di utilizzare questo dispositivo o desideri accedere a un altro account.";
"auth_softlogout_reason" = "L'amministratore dell'Home Server (%1$@) ti ha disconnesso dal tuo account %2$@ (%3$@).";
"auth_softlogout_recover_encryption_keys" = "Accedi per recuperare le chiavi crittografiche archiviate su questo dispositivo. Le chiavi ti servono per poter leggere i tuoi messaggi cifrati su altri dispositivi.";
"auth_softlogout_clear_data" = "Cancella i dati personali";
"auth_softlogout_clear_data_message_1" = "Avviso: i tuoi dati personali (comprese le chiavi crittografiche) sono ancora memorizzati su questo dispositivo.";
"auth_softlogout_clear_data_message_2" = "Cancella se hai finito di utilizzare questo dispositivo o desideri accedere a un altro account.";
"auth_softlogout_clear_data_button" = "Cancella tutti i dati";
"auth_softlogout_clear_data_sign_out_title" = "Sei sicuro?";
"auth_softlogout_clear_data_sign_out_msg" = "Sei sicuro di voler cancellare tutti i dati attualmente memorizzati su questo dispositivo? Accedi di nuovo per accedere ai dati e ai messaggi del tuo account.";
"auth_softlogout_clear_data_sign_out" = "disconnessione";
"room_creation_error_invite_user_by_email_without_identity_server" = "Nessuna identità server è configurata, quindi non è possibile aggiungere un partecipante con un'e-mail.";
"room_participants_start_new_chat_error_using_user_email_without_identity_server" = "Non è stato configurato alcun Identity Server, quindi non è possibile avviare una chat con un contatto tramite e-mail.";
"auth_softlogout_clear_data_sign_out_msg" = "Sei sicuro di voler cancellare tutti i dati memorizzati su questo dispositivo? Accedi di nuovo per gestire dati e messaggi del tuo account.";
"auth_softlogout_clear_data_sign_out" = "Disconnessione";
"room_creation_error_invite_user_by_email_without_identity_server" = "Non è stato configuato nessun Identity Server e quindi non è possibile aggiungere partecipanti con un'e-mail.";
"room_participants_start_new_chat_error_using_user_email_without_identity_server" = "Non è stato configurato alcun Identity Server, quindi non è possibile avviare una chat con qualcuno tramite e-mail.";
"room_event_action_reply" = "Rispondi";
"room_event_action_edit" = "Modifica";
"room_event_action_reaction_show_all" = "Mostra tutto";
@ -681,7 +681,7 @@
"room_message_edits_history_title" = "Modifica messaggio";
"settings_labs_message_reaction" = "Reagisci ai messaggi con emoji";
"room_participants_remove_third_party_invite_prompt_msg" = "Sei sicuro di voler revocare l'invito?";
"settings_key_backup_button_connect" = "Connetti questo dispositivo al Backup delle Chiavi";
"settings_key_backup_button_connect" = "Connetti questo dispositivo al Backup delle chiavi";
// Media picker
"media_picker_title" = "Media library";
// Image picker
@ -709,7 +709,7 @@
"device_verification_error_cannot_load_device" = "Non si riescono a recuperare le informazioni riguardanti il dipositivo.";
// Mark: Incoming
"device_verification_incoming_title" = "Richiesta di verifica in corso";
"device_verification_incoming_description_1" = "Verifica questo dispositivo per contrassegnarlo come fidato. Verificare che i dispositivi dei tuoi contatti siano fidati dà maggiore tranquillità quando usi messaggi crittografati da-utente-a-utente con loro.";
"device_verification_incoming_description_1" = "Verifica questo dispositivo per contrassegnarlo come fidato. Verificare che i dispositivi dei tuoi contatti siano fidati offre maggior sicurezza quando scambi messaggi cifrati con loro.";
"device_verification_incoming_description_2" = "Effettuando la verifica, il tuo dispositivo e quello del tuo contatto verranno reciprocamente contrassegnati come fidati.";
// MARK: Start
"device_verification_start_title" = "Verifica confrontando un breve testo";
@ -724,7 +724,7 @@
// MARK: Verified
"device_verification_verified_title" = "Verificato!";
"device_verification_verified_description_1" = "Hai verificato correttamente questo dispositivo.";
"device_verification_verified_description_2" = "Rendi sicuri i tuoi messaggi con questo contatto usando la crittografia da-utente-a-utente in modo che nessun'altro possa leggerli.";
"device_verification_verified_description_2" = "Cifra i messaggi che scambi con questo contatti in modo che nessun'altro possa leggerli.";
"device_verification_verified_got_it_button" = "Fatto";
// MARK: Emoji
"device_verification_emoji_dog" = "Cane";
@ -807,8 +807,8 @@
// MARK: Reaction history
"reaction_history_title" = "Reazioni";
// Errors
"error_user_already_logged_in" = "Sembra tu stia tentando di connetterti ad un altro Homeserver. Vuoi disconnetterti?";
"room_accessiblity_scroll_to_bottom" = "Scorri in fondo";
"error_user_already_logged_in" = "Sembra tu stia tentando di connetterti ad un altro Home Server. Vuoi disconnetterti?";
"room_accessiblity_scroll_to_bottom" = "Scorri fino in fondo";
"room_accessibility_search" = "Cerca";
"room_accessibility_integrations" = "Integrazioni";
"room_accessibility_upload" = "Invia";
@ -819,60 +819,60 @@
"media_type_accessibility_video" = "Video";
"media_type_accessibility_location" = "Posizione";
"media_type_accessibility_file" = "File";
"media_type_accessibility_sticker" = "Adesivo";
"media_type_accessibility_sticker" = "Sticker";
// Widget Picker
"widget_picker_title" = "Integrazioni";
"auth_add_email_message_2" = "Imposta un'email per il recupero dell'account, più tardi anche per essere trovabile dalle persone che ti conoscono.";
"auth_add_phone_message_2" = "Imposta un telefono, più tardi anche per essere trovabile dalle persone che ti conoscono.";
"auth_add_email_phone_message_2" = "Imposta un'email per il recupero dell'account. Più tardi usa l'email o il telefono per essere trovabile dalle persone che ti conoscono.";
"auth_email_is_required" = "Nessun server di identità configurato, perciò non puoi aggiungere un indirizzo email per ripristinare la password in futuro.";
"auth_phone_is_required" = "Nessun server di identità configurato, perciò non puoi aggiungere un numero di telefono per ripristinare la password in futuro.";
"auth_reset_password_error_is_required" = "Nessun server di identità configurato: aggiungine uno nelle opzioni server per ripristinare la password.";
"contacts_address_book_no_identity_server" = "Nessun server di identità configurato";
"auth_add_email_message_2" = "Imposta un'email per il ripristino dell'account in caso di problemi e, se vuoi, anche per farti trovare da chi conosce quell'indirizzo email.";
"auth_add_phone_message_2" = "Aggiungi un numero di telefono se vuoi farti trovare da chi lo conosce.";
"auth_add_email_phone_message_2" = "Imposta un'email per il ripristino dell'account in caso di problemi. Email e telefono potranno essere usati anche per farti trovare dagli altri utenti.";
"auth_email_is_required" = "Non è stato configurato alcun Identity Server perciò non puoi aggiungere un indirizzo email utile a ripristinare la password in caso di problemi.";
"auth_phone_is_required" = "Non è stato configurato alcun Identity Server perciò non puoi aggiungere un numero di telefono utile a ripristinare la password in caso di problemi.";
"auth_reset_password_error_is_required" = "Non è stato configurato alcun Identity Server: aggiungine uno nelle opzioni server per poter ripristinare la password.";
"contacts_address_book_no_identity_server" = "Nessun Identity Server configurato";
"settings_discovery_settings" = "SCOPRI";
"settings_identity_server_settings" = "SERVER IDENTITÀ";
"settings_three_pids_management_information_part1" = "Gestisci qui quali indirizzi email o numeri di telefono puoi usare per accedere o recuperare l'account. Controlla chi può trovarti in ";
"settings_identity_server_settings" = "IDENTITY SERVER";
"settings_three_pids_management_information_part1" = "Configura gli indirizzi email o numeri di telefono che puoi usare per accedere o per ripristinare l'account in caso di problemi. Controlla chi può trovarti in ";
"settings_three_pids_management_information_part2" = "Scopri";
"settings_three_pids_management_information_part3" = ".";
"settings_calls_stun_server_fallback_button" = "Permetti server di assistenza alle chiamate di fallback";
"settings_calls_stun_server_fallback_description" = "Consenti server di assistenza alle chiamate di fallback %@ quando il tuo homeserver non ne offre uno (il tuo indirizzo IP verrà condiviso durante una chiamata).";
"settings_devices_description" = "Il nome pubblico di un dispositivo è visibile dalle persone con cui comunichi";
"settings_discovery_no_identity_server" = "Attualmente non stai usando un server di identità. Per essere trovabile dai contatti esistenti che conosci, aggiungine uno.";
"settings_discovery_terms_not_signed" = "Accetta le condizioni di servizio del server di identità (%@) per poter essere trovabile tramite indirizzo email o numero di telefono.";
"settings_discovery_three_pids_management_information_part1" = "Gestisci quali indirizzi email o numeri di telefono gli altri utenti possono usare per trovarti e invitarti nelle stanze. Aggiungi o rimuovi indirizzi email o numeri di telefono da questa lista in ";
"settings_calls_stun_server_fallback_button" = "Permetti chiamate dal Server di appoggio";
"settings_calls_stun_server_fallback_description" = "Se il tuo Home Server non ne ha un proprio Server d'appoggio verrà usato %s (il Server d'appoggio verrà a conoscenza del tuo indirizzo IP durante le chiamate).";
"settings_devices_description" = "Il nome pubblico di un dispositivo è visibile alle persone con cui comunichi";
"settings_discovery_no_identity_server" = "In questo momento non stai usando alcun Identity Server. Per trovare e farti trovare dagli altri utenti, configurane uno qua sotto.";
"settings_discovery_terms_not_signed" = "Accetta i termini di servizio dell'Identity Server (%@) per permettere ad altri utenti di trovarti tramite la tua email o numero di telefono.";
"settings_discovery_three_pids_management_information_part1" = "Configura gli indirizzi email o numeri di telefono con cui gli altri utenti potranno trovarti e invitarti nelle stanze. Aggiungi o rimuovi indirizzi email o numeri di telefono da questa lista in ";
"settings_discovery_three_pids_management_information_part2" = "Impostazioni utente";
"settings_discovery_three_pids_management_information_part3" = ".";
"settings_discovery_error_message" = "C'è stato un errore. Riprova.";
"settings_discovery_three_pid_details_title_email" = "Gestisci email";
"settings_discovery_three_pid_details_information_email" = "Gestisci le impostazioni di questo indirizzo email che altri utenti possono usare per trovarti o invitarti in altre stanze. Aggiungi o rimuovi gli indirizzi email in Accounts.";
"settings_discovery_three_pid_details_title_phone_number" = "Gestisci il numero di telefono";
"settings_discovery_three_pid_details_information_phone_number" = "Gestisci le impostazioni di questo numero di telefono che altri utenti possono usare per trovarti o invitarti in altre stanze. Aggiungi o rimuovi i numeri di telefono in Accounts.";
"settings_discovery_three_pid_details_information_email" = "Configura le impostazioni di questo indirizzo email che altri utenti potranno usare per trovarti o invitarti in altre stanze. Aggiungi o rimuovi gli indirizzi email in Accounts.";
"settings_discovery_three_pid_details_title_phone_number" = "Configura il numero di telefono";
"settings_discovery_three_pid_details_information_phone_number" = "Configura le impostazioni di questo numero di telefono che altri utenti possono usare per trovarti o invitarti in altre stanze. Aggiungi o rimuovi i numeri di telefono in Accounts.";
"settings_discovery_three_pid_details_share_action" = "Condividi";
"settings_discovery_three_pid_details_revoke_action" = "Cancella";
"settings_discovery_three_pid_details_cancel_email_validation_action" = "Annulla la validazione dell'email";
"settings_discovery_three_pid_details_enter_sms_code_action" = "Inserisci il codice d'attivazione SMS";
"settings_identity_server_description" = "Utilizzando l'Identity Server impostato potrai trovare e farti trovare dai contatti esistenti.";
"settings_identity_server_no_is" = "Nessun Identity Server configurato";
"settings_identity_server_no_is" = "Non è stato configurato alcun Identity Server";
"settings_identity_server_no_is_description" = "Non stai usando alcun Identity Server. Selezionane uno per trovare e farti trovare dai contatti esistenti.";
// Identity server settings
"identity_server_settings_title" = "// Impostazioni dell'Identity Server";
"identity_server_settings_title" = "Identity Server";
"identity_server_settings_description" = "Per trovare e farti trovare dai tuoi contatti stai usando %@.";
"identity_server_settings_no_is_description" = "Non stai usando alcun Identity Server. Selezionane uno per trovare e farti trovare dai contatti esistenti.";
"identity_server_settings_place_holder" = "Inserisci un Identity Server";
"identity_server_settings_add" = "Aggiungi";
"identity_server_settings_change" = "Cambia";
"identity_server_settings_disconnect_info" = "Usare un Identity Server è facoltativo. Se scegli di non usarne uno gli altri utenti non potranno trovarti e tu non potrai invitarli per email o telefono.";
"identity_server_settings_disconnect_info" = "Se ti disconnetti dall'Identity Server gli altri utenti non potranno trovarti e tu non potrai invitarne di nuovi per email o telefono.";
"identity_server_settings_disconnect" = "Disconnetti";
"identity_server_settings_alert_no_terms_title" = "L'Identity Server non ha Termini di servizio";
"identity_server_settings_alert_no_terms" = "L'Identity Server che hai scelto non ha Termini di servizio. Prosegui solo se ti fidi del gestore del server.";
"identity_server_settings_alert_no_terms_title" = "L'Identity Server non ha fornito dei termini di servizio";
"identity_server_settings_alert_no_terms" = "L'Identity Server che hai scelto non ha freso noti i propri termini di servizio. Continua solo se ti fidi.";
"identity_server_settings_alert_change_title" = "Cambia Identity Server";
"identity_server_settings_alert_change" = "Vuoi scollegarti dall'Identyty Server %1$@ e connetterti invece a %2$@?";
"identity_server_settings_alert_disconnect_title" = "Scollega dall'Identity Server";
"identity_server_settings_alert_change" = "Vuoi scollegarti dall'Identity Server %1$@ e connetterti invece a %2$@?";
"identity_server_settings_alert_disconnect_title" = "Scollega l'Identity Server";
"identity_server_settings_alert_disconnect" = "Vuoi scollegarti dall'Identity Server %@?";
"identity_server_settings_alert_disconnect_button" = "Scollega";
"identity_server_settings_alert_disconnect_still_sharing_3pid" = "L'Identity Server %@ può ancora condividere le tue informazioni personali.\n\nTi raccomandiamo di rimuovere tutti i tuoi indirizzi email e numeri di telefono dall'Identity Server prima di scollegarti.";
"identity_server_settings_alert_disconnect_still_sharing_3pid" = "L'Identity Server %@ può ancora condividere le tue informazioni personali.\n\nTi raccomandiamo di rimuovere tutti i tuoi indirizzi email e numeri di telefono dall'Identity Server prima di scollegarlo.";
"identity_server_settings_alert_disconnect_still_sharing_3pid_button" = "Scollegati comunque";
"identity_server_settings_alert_error_terms_not_accepted" = "Devi accettare le condizioni di %@ per impostarlo come tuo Identity Server.";
"identity_server_settings_alert_error_terms_not_accepted" = "Devi accettare i termini di servizio di %@ per poterlo impostare come tuo Identity Server.";
"identity_server_settings_alert_error_invalid_identity_server" = "%@ non é un Identity Server valido.";
"call_no_stun_server_error_title" = "Chiamata fallita a causa di una configurazione errata del server";
"call_no_stun_server_error_message_1" = "Chiedi all'amministratore del tuo Homeserver %@ di configurare un server TURN in modo che le chiamate funzionino come si deve.";
@ -897,7 +897,7 @@
"widget_menu_remove" = "Rimuovi per tutti";
"settings_integrations" = "INTEGRAZIONI";
"settings_integrations_allow_button" = "Gestisci le integrazioni";
"settings_integrations_allow_description" = "Usa un gestore di integrazioni (%@) per gestire bot, bridge, widget e pacchetti di adesivi.\n\nI gestori di integrazione ricevono dati di configurazione e possono modificare widget, inviare inviti alla stanza, assegnare permessi a tuo nome.";
"settings_integrations_allow_description" = "Usa un Integration Manager (%@) per gestire bot, bridge, widget e pacchetti di sticker.\n\nGli Integration Manager possono ricevere dati di configurazione, modificare widget, mandare inviti alle stanze e modificare permessi a tuo nome.";
"widget_integration_manager_disabled" = "Devi attivare il gestore di integrazioni nelle impostazioni";
// Room widget permissions
"room_widget_permission_title" = "Carica widget";
@ -914,5 +914,71 @@
"accessibility_checkbox_label" = "checkbox";
"widget_picker_manage_integrations" = "Gestisci integrazioni...";
"service_terms_modal_policy_checkbox_accessibility_hint" = "Seleziona per accettare %@";
"settings_labs_dm_key_verification" = "Verifica chiave via messaggio diretto";
"settings_labs_dm_key_verification" = "Verifica chiave con messaggio diretto";
"settings_labs_cross_signing" = "Firma incrociata";
"key_verification_tile_request_incoming_title" = "Richiesta di verifica";
"key_verification_tile_request_outgoing_title" = "Verifica inviata";
"key_verification_tile_request_status_data_loading" = "Caricamento dati…";
"key_verification_tile_request_status_waiting" = "In attesa…";
"key_verification_tile_request_status_expired" = "Scaduta";
"key_verification_tile_request_status_cancelled_by_me" = "Hai annullato";
"key_verification_tile_request_status_cancelled" = "%@ ha annullato";
"key_verification_tile_request_status_accepted" = "Hai accettato";
"key_verification_tile_request_incoming_approval_accept" = "Accetta";
"key_verification_tile_request_incoming_approval_decline" = "Rifiuta";
"key_verification_tile_conclusion_done_title" = "Verificato";
"key_verification_tile_conclusion_warning_title" = "Accesso non fidato";
"key_verification_incoming_request_incoming_alert_message" = "%@ vuole verificare";
"settings_labs_enable_cross_signing" = "Attiva la firma incrociata per la verifica per-utente invece di per-dispositivo (in sviluppo)";
"settings_security" = "SICUREZZA";
// Security settings
"security_settings_title" = "Sicurezza";
"security_settings_crypto_sessions" = "MIE SESSIONI";
"security_settings_crypto_sessions_description" = "Verifica le sessioni per dare l'accesso ai messaggi cifrati end-to-end. Se non riconosci una sessione, modifica la password di accesso e reimposta la Password Messaggio usata per il Backup Messaggi.";
"security_settings_backup" = "BACKUP MESSAGGI";
"security_settings_advanced" = "AVANZATE";
"security_settings_blacklist_unverified_devices" = "Non inviare mai messaggi a sessioni non fidate";
"security_settings_blacklist_unverified_devices_description" = "Verifica tutte le sessioni di un utente per marcarle come fidate ed invirvi messaggi.";
"security_settings_export_keys_manually" = "Esporta manualmente le chiavi";
// Manage session
"manage_session_title" = "Gestisci sessione";
"manage_session_info" = "INFO SESSIONE";
"manage_session_name" = "Nome dispositivo";
"manage_session_trusted" = "Di tua fiducia";
"manage_session_not_trusted" = "Non fidato";
"manage_session_sign_out" = "Disconnetti da questo dispositivo";
"room_participants_action_section_security" = "Sicurezza";
"room_participants_action_security_status_verified" = "Verificato";
"room_participants_action_security_status_verify" = "Verifica";
"room_participants_action_security_status_warning" = "Attenzione";
"room_participants_security_loading" = "Caricamento…";
"key_verification_user_title" = "Verifica utente";
"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.";
"key_verification_verify_user_title_number" = "Verifica questo utente confermando che i seguenti numeri appaiono sul suo schermo, nello stesso ordine.";
"key_verification_verified_user_description_1" = "Hai verificato correttamente questo utente.";
"key_verification_verified_user_description_2" = "I messaggi con questo utente in questa stanza sono cifrati end-to-end e non possono essere letti da terze parti.";
"user_verification_start_verify_action" = "Inizia la verifica";
"user_verification_start_information_part1" = "Per maggiore sicurezza, verifica ";
"user_verification_start_information_part2" = " controllando un codice univoco in entrambi i dispositivi.";
"user_verification_start_waiting_partner" = "In attesa di %@…";
"user_verification_start_additional_information" = "Per sicurezza, fatelo di persona o usate un altro metodo di comunicazione.";
"user_verification_sessions_list_user_trust_level_trusted_title" = "Fidati";
"user_verification_sessions_list_user_trust_level_warning_title" = "Attenzione";
"user_verification_sessions_list_user_trust_level_unknown_title" = "Sconosciuti";
"user_verification_sessions_list_information" = "I messaggi con questo utente in questa stanza sono cifrati end-to-end e non possono essere letti da terze parti.";
"user_verification_sessions_list_table_title" = "Sessioni";
"user_verification_sessions_list_session_trusted" = "Fidate";
"user_verification_sessions_list_session_untrusted" = "Non fidate";
"user_verification_session_details_trusted_title" = "Fidata";
"user_verification_session_details_untrusted_title" = "Attenzione";
"user_verification_session_details_information_trusted_current_user" = "Questa sessione è fidata per comunicazioni sicure perchè l'hai verificata:";
"user_verification_session_details_information_trusted_other_user_part1" = "Questo dispositivo è fidato per comunicazioni sicure perchè ";
"user_verification_session_details_information_trusted_other_user_part2" = " ha verificato:";
"user_verification_session_details_information_untrusted_current_user" = "Verifica questa sessione per marcarla come fidata e darle accesso ai messaggi cifrati:";
"user_verification_session_details_information_untrusted_other_user" = " ha fatto l'accesso con un nuovo dispositivo:";
"user_verification_session_details_additional_information_untrusted_other_user" = "Fino a quando questo utente non si fida di questo dispositivo, i messaggi inviati da e verso di esso sono marcati da avvisi. In alternativa, puoi verificarlo manualmente.";
"user_verification_session_details_additional_information_untrusted_current_user" = "Se non hai fatto l'accesso a questa sessione, il tuo account potrebbe essere compromesso.";
"user_verification_session_details_verify_action_current_user" = "Verifica";
"user_verification_session_details_verify_action_other_user" = "Verifica manualmente";

View file

@ -562,3 +562,9 @@
"room_resource_limit_exceeded_message_contact_1" = " Please ";
"settings_ui_theme_black" = "Black";
"settings_flair" = "特色を表示する";
// String for App Store
"store_short_description" = "セキュアな分散型チャット/VoIP";
"close" = "閉じる";
// Accessibility
"accessibility_checkbox_label" = "チェックボックス";
"auth_login_single_sign_on" = "シングルサインオン(SSO)でサインイン";

View file

@ -54,3 +54,4 @@
"MSG_FROM_USER_IN_ROOM_TITLE" = "%@ në %@";
/* Sticker from a specific person, not referencing a room. */
"STICKER_FROM_USER" = "%@ dërgoi një ngjitës";
"KEY_VERIFICATION_REQUEST_FROM_USER" = "%@ dëshiron të verifikojë";

View file

@ -602,18 +602,18 @@
"key_backup_recover_title" = "Mesazhe të Sigurt";
"key_backup_recover_empty_backup_title" = "Kopjeruajtje e zbrazët";
"key_backup_recover_empty_backup_message" = "Ska kyç për rikthim";
"key_backup_recover_from_passphrase_info" = "Që të shkyçni historikun e mesazheve tuaj të sigurt përdorni frazëkalimin tuaj të rikthimeve";
"key_backup_recover_from_passphrase_info" = "Që të shkyçni historikun e mesazheve tuaj të sigurt përdorni frazëkalimin tuaj të rimarrjeve";
"key_backup_recover_from_passphrase_passphrase_title" = "Jepeni";
"key_backup_recover_from_passphrase_passphrase_placeholder" = "Jepni Frazëkalimin";
"key_backup_recover_from_passphrase_recover_action" = "Shkyçeni Historikun";
"key_backup_recover_from_passphrase_lost_passphrase_action_part1" = "Nuk e dini frazëkalimin tuaj të rikthimeve? Mundeni të ";
"key_backup_recover_from_passphrase_lost_passphrase_action_part2" = "përdorni kyçin tuaj të rikthimeve";
"key_backup_recover_from_passphrase_lost_passphrase_action_part1" = "Nuk e dini frazëkalimin tuaj të rimarrjeve? Mundeni të ";
"key_backup_recover_from_passphrase_lost_passphrase_action_part2" = "përdorni kyçin tuaj të rimarrjeve";
"key_backup_recover_from_passphrase_lost_passphrase_action_part3" = ".";
"key_backup_recover_from_recovery_key_info" = "Përdorni kyçin tuaj të rikthimeve për të shkyçur historikun tuaj të mesazheve të sigurt";
"key_backup_recover_from_recovery_key_info" = "Që të shkyçni historikun e mesazheve tuaj të sigurt, përdorni frazëkalimin tuaj të rimarrjeve";
"key_backup_recover_from_recovery_key_recovery_key_title" = "Jepeni";
"key_backup_recover_from_recovery_key_recovery_key_placeholder" = "Jepni Kyç Rikthimi";
"key_backup_recover_from_recovery_key_recovery_key_placeholder" = "Jepni Kyç Rimarrjesh";
"key_backup_recover_from_recovery_key_recover_action" = "Shkyçe Historikun";
"key_backup_recover_from_recovery_key_lost_recovery_key_action" = "Humbët kyçin tuaj të rikthimeve? Te rregullimet mund të caktoni një të ri.";
"key_backup_recover_from_recovery_key_lost_recovery_key_action" = "Humbët kyçin tuaj të rimarrjeve? Te rregullimet mund të caktoni një të ri.";
"key_backup_recover_success_info" = "Kopjeruajtja u Rikthye!";
"key_backup_recover_done_action" = "U bë";
"key_backup_setup_banner_title_part1" = "Rregulloni Rikthim Mesazhesh të Sigurt";
@ -626,22 +626,22 @@
"key_backup_setup_intro_setup_action_without_existing_backup" = "Fillo të përdorësh Kopjeruajtje Kyçesh";
"key_backup_setup_intro_setup_action_with_existing_backup" = "Përdor Kopjeruajtje Kyçesh";
"key_backup_setup_passphrase_title" = "Sigurojeni kopjeruajtjen tuaj me një Frazëkalim";
"key_backup_setup_passphrase_setup_recovery_key_info" = "Ose, sigurojeni kopjeruajtjen tuaj me një Kyç Rikthimesh, duke e ruajtur këtë diku të parrezikuar.";
"key_backup_setup_passphrase_setup_recovery_key_action" = "(Të mëtejshme) Rregullojeni me një Kyç Rikthimesh";
"key_backup_setup_passphrase_setup_recovery_key_info" = "Ose, sigurojeni kopjeruajtjen tuaj me një Kyç Rimarrjesh, duke e ruajtur këtë diku të parrezikuar.";
"key_backup_setup_passphrase_setup_recovery_key_action" = "(Të mëtejshme) Rregullojeni me një Kyç Rimarrjesh";
"key_backup_setup_success_title" = "Sukses!";
// Success from passphrase
"key_backup_setup_success_from_passphrase_info" = "Po bëhet kopjeruajtja për kyçet tuaj.\n\nKyçi juaj i rikthimeve është një lloj rrjeti sigurie - mund ta përdorni për të rifituar hyrje te mesazhet tuaj të fshehtëzuar, nëse harroni frazëkalimin tuaj.\n\nMbajeni kyçin tuaj të rikthimeve diku shumë të sigurt, bie fjala, nën një përgjegjës fjalëkalimesh (ose në një kasafortë).";
"key_backup_setup_success_from_passphrase_save_recovery_key_action" = "Ruani Kyç Rikthimesh";
"key_backup_setup_success_from_passphrase_info" = "Po bëhet kopjeruajtja për kyçet tuaj.\n\nKyçi juaj i rimarrjeve është një lloj mase sigurie - mund ta përdorni për të rifituar hyrje te mesazhet tuaj të fshehtëzuar, nëse harroni frazëkalimin tuaj.\n\nMbajeni kyçin tuaj të rimarrjeve diku shumë të sigurt, bie fjala, nën një përgjegjës fjalëkalimesh (ose në një kasafortë).";
"key_backup_setup_success_from_passphrase_save_recovery_key_action" = "Ruani Kyç Rimarrjesh";
"key_backup_setup_success_from_passphrase_done_action" = "U krye";
// Success from recovery key
"key_backup_setup_success_from_recovery_key_info" = "Po bëhet kopjeruajtja për kyçet tuaj.\n\nBëni një kopje të këtij kyçi rikthimesh dhe mbajeni të parrezikuar.";
"key_backup_setup_success_from_recovery_key_recovery_key_title" = "Kyç Rikthimesh";
"key_backup_setup_success_from_recovery_key_info" = "Po bëhet kopjeruajtja për kyçet tuaj.\n\nBëni një kopje të këtij kyçi rimarrjesh dhe mbajeni të parrezikuar.";
"key_backup_setup_success_from_recovery_key_recovery_key_title" = "Kyç Rimarrjesh";
"key_backup_setup_success_from_recovery_key_make_copy_action" = "Bëni një Kopje";
"key_backup_setup_success_from_recovery_key_made_copy_action" = "Kam bërë një kopje";
"key_backup_recover_invalid_passphrase_title" = "Frazëkalim Rikthimi i Pasaktë";
"key_backup_recover_invalid_passphrase" = "Su shfshehtëzua dot kopjeruajtja me këtë frazëkalim: ju lutemi, verifikoni që dhatë frazëkalimin e duhur të rikthimeve.";
"key_backup_recover_invalid_recovery_key_title" = "Mospërputhje Kyçesh Rikthimi";
"key_backup_recover_invalid_recovery_key" = "Nuk u shfshehtëzua dot kopjeruajtja me këtë kyç: ju lutemi, verifikoni që dhatë kyçin e duhur të rikthimeve.";
"key_backup_recover_invalid_passphrase_title" = "Frazëkalim Rimarrjeje i Pasaktë";
"key_backup_recover_invalid_passphrase" = "Su shfshehtëzua dot kopjeruajtja me këtë frazëkalim: ju lutemi, verifikoni që dhatë frazëkalimin e duhur të rimarrjeve.";
"key_backup_recover_invalid_recovery_key_title" = "Mospërputhje Kyçesh Rimarrjeje";
"key_backup_recover_invalid_recovery_key" = "Nuk u shfshehtëzua dot kopjeruajtja me këtë kyç: ju lutemi, verifikoni që dhatë kyçin e duhur të rimarrjeve.";
"key_backup_setup_banner_title" = "Mos humbni kurrë mesazhe të fshehtëzuar";
"key_backup_setup_banner_subtitle" = "Fillo të përdorësh Kopjeruajtje Kyçesh";
"key_backup_recover_banner_title" = "Mos humbni kurrë mesazhe të fshehtëzuar";
@ -933,3 +933,21 @@
"room_widget_permission_widget_id_permission" = "ID Widget-i";
"room_widget_permission_room_id_permission" = "ID Dhome";
"service_terms_modal_policy_checkbox_accessibility_hint" = "I vini shenjë që të pranohet %@";
"settings_labs_dm_key_verification" = "Verifikim kyçesh përmes mesazhi të drejtpërdrejtë";
"settings_labs_cross_signing" = "Nënshkrim kryq";
"settings_labs" = "LABS";
"settings_calls_stun_server_fallback_button" = "Lejoni shërbyes rrugëzgjidhje asistimi thirrjesh";
"settings_calls_stun_server_fallback_description" = "Lejoni shërbyes rrugëzgjidhje asistimi thirrjesh %@, kur shërbyesi juaj Home nuk ofron një të tillë (gjatë thirrjes, adresa juaj IP do ti bëhet e ditur)";
"key_verification_tile_request_incoming_title" = "Kërkesë verifikimi";
"key_verification_tile_request_outgoing_title" = "Email-i i verifikimit u dërgua";
"key_verification_tile_request_status_data_loading" = "Ngarkim të dhënat…";
"key_verification_tile_request_status_waiting" = "Në pritje…";
"key_verification_tile_request_status_expired" = "I skaduar";
"key_verification_tile_request_status_cancelled_by_me" = "Anuluat";
"key_verification_tile_request_status_cancelled" = "%@ u anulua";
"key_verification_tile_request_status_accepted" = "Pranuat";
"key_verification_tile_request_incoming_approval_accept" = "Pranoje";
"key_verification_tile_request_incoming_approval_decline" = "Hidhe poshtë";
"key_verification_tile_conclusion_done_title" = "I verifikuar";
"key_verification_tile_conclusion_warning_title" = "Hyrje jo e besuar në";
"key_verification_incoming_request_incoming_alert_message" = "%s dëshiron të verifikojë";

View file

@ -1376,6 +1376,55 @@
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</pre>
</li>
<li>
<b>DGCollectionViewLeftAlignFlowLayout</b> (<a href="https://github.com/Digipolitan/collection-view-left-align-flow-layout">https://github.com/Digipolitan/collection-view-left-align-flow-layout</a>)
<br/><br/>This is a simple layout that align does not try to fulfill the lines but stick elements to the left.
<br/><br/>DGCollectionViewLeftAlignFlowLayout is licensed under the BSD 3-Clause license.
<br/>Copyright (c) 2017, Digipolitan All rights reserved.
<br/><br/>Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
<br/><br/>- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
<br/><br/>- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
<br/><br/>- Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
<br/><br/>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<br/><br/>
</li>
<li>
<b>KTCenterFlowLayout</b> (<a href="https://github.com/keighl/KTCenterFlowLayout">https://github.com/keighl/KTCenterFlowLayout</a>)
<br/><br/>KTCenterFlowLayout is a subclass of UICollectionViewFlowLayout which Aligns cells to the center of a collection view.
<br/><br/>It is released under the MIT license.
<br/><br/>Copyright (c) keighl (http://github.com/keighl)
<br/><br/>Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
<br/><br/>The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
<br/><br/>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
<br/><br/>
</li>
</ul>
</body>
</html>

View file

@ -2,4 +2,5 @@
"NSCameraUsageDescription" = "Камера використовується для знімків фото і відео, а також для відео-викликів.";
"NSPhotoLibraryUsageDescription" = "Фотографії використовуються для надсилання фото і відео.";
"NSMicrophoneUsageDescription" = "Мікрофон використовується для відео і викликів.";
"NSContactsUsageDescription" = "Щоб показати, які з ваших контактів вже використовують Riot чи Matrix, ми можемо надіслати адреси електронної пошти і номери телефонів з вашої адресної книги до вашого сервера ідентифікації Matrix. Новий Vector не зберігає і не використовує ці дані. Для докладних відомостей ознайомтеся зі сторінкою політики приватності в налаштуваннях додатку.";
"NSContactsUsageDescription" = "Щоб показати, які з ваших контактів вже використовують Matrix, Riot може надіслати адреси електронної пошти і номери телефонів з вашої адресної книги до вашого ідентифікаційного сервера Matrix. При наявності підтримки, перед надсиланням створюється хеш особистих даних. Для докладних відомостей ознайомтеся з політикою приватності свого ідентифікаційного сервера.";
"NSCalendarsUsageDescription" = "Переглядайте свої заплановані зустрічі в додатку.";

View file

@ -1,5 +1,5 @@
/* New message from a specific person, not referencing a room */
"MSG_FROM_USER" = "Повідомлення від %@";
"MSG_FROM_USER" = "%@ надсилає повідомлення";
/* New message from a specific person in a named room */
"MSG_FROM_USER_IN_ROOM" = "%@ пише в %@";
/* New message from a specific person, not referencing a room. Content included. */
@ -11,7 +11,7 @@
/* New action message from a specific person in a named room. */
"ACTION_FROM_USER_IN_ROOM" = "%@: * %@ %@";
/* New action message from a specific person, not referencing a room. */
"IMAGE_FROM_USER" = "%@ надсилає вам зображення %@";
"IMAGE_FROM_USER" = "%@ надсилає зображення %@";
/* New action message from a specific person in a named room. */
"IMAGE_FROM_USER_IN_ROOM" = "%@ оприлюднює зображення %@ в %@";
/* A single unread message in a room */
@ -50,3 +50,7 @@
"VOICE_CONF_NAMED_FROM_USER" = "Груповий виклик від %@: '%@'";
/* Incoming named video conference invite from a specific person */
"VIDEO_CONF_NAMED_FROM_USER" = "Груповий відео-виклик від %@: '%@'";
/* Message title for a specific person in a named room */
"MSG_FROM_USER_IN_ROOM_TITLE" = "%@ в %@";
/* Sticker from a specific person, not referencing a room. */
"STICKER_FROM_USER" = "%@ надсилає наліпку";

View file

@ -52,7 +52,7 @@
"auth_repeat_password_placeholder" = "Повторіть пароль";
"auth_repeat_new_password_placeholder" = "Підтвердьте новий пароль";
"auth_home_server_placeholder" = "URL (наприклад, https://matrix.org)";
"auth_identity_server_placeholder" = "URL (наприклад, https://matrix.org)";
"auth_identity_server_placeholder" = "URL (наприклад, https://vector.im)";
"auth_invalid_login_param" = "Неправильне ім'я користувача або пароль";
"auth_invalid_user_name" = "Імена користувачів можуть містити лише літери, цифри, крапки, дефіси й підкреслення";
"auth_invalid_password" = "Пароль надто короткий (мінімум 6 знаків)";
@ -81,3 +81,55 @@
"auth_recaptcha_message" = "Цей домашній сервер бажає переконатися, що ви не робот";
"auth_reset_password_message" = "Щоб відновити пароль, введіть адресу е-пошти, пов'язану з вашим обліковим записом:";
"auth_reset_password_missing_email" = "Необхідно ввести адресу е-пошти, пов'язану з вашим обліковим записом.";
// String for App Store
"store_short_description" = "Захищений, децентралізований чат/VoIP";
"close" = "Закрити";
// Accessibility
"accessibility_checkbox_label" = "прапорець";
"auth_add_email_message_2" = "Вкажіть е-пошту для відновлення облікового запису, а також для можливості знаходження вас іншими користувачами.";
"auth_add_phone_message_2" = "Вкажіть номер телефону для можливості знаходження вас іншими користувачами.";
"auth_add_email_phone_message_2" = "Вкажіть е-пошту для відновлення облікового запису. Використовуйте електронну пошту чи номер телефону для можливості знаходження вас іншими користувачами.";
"auth_email_is_required" = "Ідентифікаційний сервер не налаштовано, тому ви не можете додати адресу електронної пошти, щоб мати можливість відновити пароль в майбутньому.";
"auth_phone_is_required" = "Ідентифікаційний сервер не налаштовано, тому ви не можете додати номер телефону, щоб мати можливість відновити пароль в майбутньому.";
"auth_forgot_password_error_no_configured_identity_server" = "Ідентифікаційний сервер не налаштовано: додайте його, щоб мати можливість відновити пароль в майбутньому.";
"auth_reset_password_missing_password" = "Необхідно ввести новий пароль.";
"auth_reset_password_email_validation_message" = "На адресу %@ надіслано лист. Після переходу за посиланням в листі, натисніть внизу.";
"auth_reset_password_next_step_button" = "Я підтверджую свою адресу е-пошти";
"auth_reset_password_error_unauthorized" = "Не вдалося перевірити е-пошту: переконайтеся, що ви перейшли за посиланням у листі";
"auth_reset_password_error_not_found" = "Схоже, ваша адреса електронної пошти не пов'язана з жодним Matrix ID на цьому домашньому сервері.";
"auth_reset_password_error_is_required" = "Ідентифікаційний сервер не налаштовано: додайте його в параметрах сервера, щоб мати можливість відновити пароль в майбутньому.";
"auth_reset_password_success_message" = "Ваш пароль було відновлено.\n\nСеанс входу завершено на всіх пристроях і припинено отримання push-сповіщень. Щоб активувати сповіщення, виконайте вхід з новим паролем на кожному пристрої.";
"auth_add_email_and_phone_warning" = "Реєстрація за допомогою електронної пошти і номера телефону водночас не підтримується, доки немає API. Лише номер телефону буде додано до облікового запису. Ви можете додати електронну пошту до свого профілю в налаштуваннях.";
"auth_accept_policies" = "Ознайомтесь та прийміть правила цього домашнього сервера:";
"auth_softlogout_signed_out" = "Ви вийшли";
"auth_softlogout_sign_in" = "Увійти";
"auth_softlogout_reason" = "Адміністратор вашого домашнього сервера (%1$@) завершив сеанс вашого облікового запису %2$@ (%3$@).";
"auth_softlogout_recover_encryption_keys" = "Увійдіть для відновлення ключів шифрування, що зберігаються тільки на цьому пристрої. Вам вони необхідні для прочитання всіх ваших захищених повідомлень на будь-якому пристрої.";
"auth_softlogout_clear_data" = "Стерти особисті дані";
"auth_softlogout_clear_data_message_1" = "Попередження: Ваші особисті дані (включно з ключами шифрування) все ще зберігаються на цьому пристрої.";
"auth_softlogout_clear_data_message_2" = "Зітріть, якщо ви припинили користуватися цим пристроєм, або хочете увійти в інший обліковий запис.";
"auth_softlogout_clear_data_button" = "Стерти всі дані";
"auth_softlogout_clear_data_sign_out_title" = "Ви впевнені?";
"auth_softlogout_clear_data_sign_out_msg" = "Ви справді хочете стерти всі дані, що зберігаються на цьому пристрої? Увійдіть знову для доступу до даних і повідомлень свого облікового запису.";
"auth_softlogout_clear_data_sign_out" = "Вийти";
"room_resource_limit_exceeded_message_contact_1" = " Будь ласка, ";
// Generic errors
"error_invite_3pid_with_no_identity_server" = "Додайте ідентифікаційний сервер в параметрах, щоб запросити е-поштою.";
"error_not_supported_on_mobile" = "Ви не можете робити це з %@ мобільного.";
// Errors
"error_user_already_logged_in" = "Схоже, ви намагаєтесь з'єднатися до іншого домашнього сервера. Хочете вийти?";
// Chat creation
"room_creation_title" = "Новий чат";
"room_creation_account" = "Обліковий запис";
"room_creation_appearance" = "Зовнішній вигляд";
"room_creation_appearance_name" = "Назва";
"room_creation_appearance_picture" = "Зображення чату (необов'язково)";
"room_creation_privacy" = "Приватність";
"room_creation_private_room" = "Цей чат є приватним";
"room_creation_public_room" = "Цей чат є публічним";
"room_creation_make_public" = "Зробити публічним";
"room_creation_make_public_prompt_title" = "Зробити цей чат публічним?";
"room_creation_make_public_prompt_msg" = "Ви справді хочете зробити цей чат публічним? Будь-хто зможе долучатися й читати повідомлення.";
"room_creation_keep_private" = "Залишити приватним";
"room_creation_make_private" = "Зробити приватним";
"room_creation_wait_for_creation" = "Триває створення кімнати. Будь ласка, зачекайте.";

View file

@ -42,6 +42,20 @@ extern NSString *const kMXKRoomBubbleCellLongPressOnReactionView;
*/
extern NSString *const kMXKRoomBubbleCellEventIdKey;
/**
Action identifier used when the user pressed accept button for an incoming key verification request.
The `userInfo` dictionary contains an `NSString` object under the `kMXKRoomBubbleCellEventIdKey` key, representing the event id associated to the key verification request.
*/
extern NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestAcceptPressed;
/**
Action identifier used when the user pressed decline button for an incoming key verification request.
The `userInfo` dictionary contains an `NSString` object under the `kMXKRoomBubbleCellEventIdKey` key, representing the event id associated to the key verification request.
*/
extern NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed;
/**
Define a `MXKRoomBubbleTableViewCell` category at Riot level to handle bubble customisation.
*/

View file

@ -31,6 +31,8 @@ NSString *const kMXKRoomBubbleCellRiotEditButtonPressed = @"kMXKRoomBubbleCellRi
NSString *const kMXKRoomBubbleCellTapOnReceiptsContainer = @"kMXKRoomBubbleCellTapOnReceiptsContainer";
NSString *const kMXKRoomBubbleCellLongPressOnReactionView = @"kMXKRoomBubbleCellLongPressOnReactionView";
NSString *const kMXKRoomBubbleCellEventIdKey = @"kMXKRoomBubbleCellEventIdKey";
NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestAcceptPressed = @"kMXKRoomBubbleCellKeyVerificationAcceptPressed";
NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed = @"kMXKRoomBubbleCellKeyVerificationDeclinePressed";
@implementation MXKRoomBubbleTableViewCell (Riot)
@ -76,6 +78,12 @@ NSString *const kMXKRoomBubbleCellEventIdKey = @"kMXKRoomBubbleCellEventIdKey";
viewTag:(NSInteger)viewTag
displayOnLeft:(BOOL)displayOnLeft
{
if (!self.bubbleInfoContainer)
{
NSLog(@"[MXKRoomBubbleTableViewCell+Riot] bubbleInfoContainer property is missing for cell class: %@", NSStringFromClass(self.class));
return;
}
NSArray *bubbleComponents = bubbleData.bubbleComponents;
MXKRoomBubbleComponent *component = bubbleComponents[componentIndex];

View file

@ -17,6 +17,8 @@
#import <MatrixKit/MatrixKit.h>
#import "UserEncryptionTrustLevel.h"
/**
Define a `MXRoom` category at Riot level.
*/
@ -75,4 +77,11 @@
*/
- (void)allMessages:(void (^)(void))completion;
/**
Get user encryption trust level.
@param userId The user id.
*/
- (UserEncryptionTrustLevel)encryptionTrustLevelForUserId:(NSString*)userId;
@end

View file

@ -324,6 +324,37 @@
}
}
- (UserEncryptionTrustLevel)encryptionTrustLevelForUserId:(NSString*)userId
{
UserEncryptionTrustLevel userEncryptionTrustLevel;
if (self.mxSession.crypto)
{
MXUsersTrustLevelSummary *usersTrustLevelSummary = [self.mxSession.crypto trustLevelSummaryForUserIds:@[userId]];
double trustedDevicesPercentage = usersTrustLevelSummary.trustedDevicesProgress.fractionCompleted;
if (trustedDevicesPercentage >= 1.0)
{
userEncryptionTrustLevel = UserEncryptionTrustLevelTrusted;
}
else if (trustedDevicesPercentage == 0.0)
{
userEncryptionTrustLevel = UserEncryptionTrustLevelNormal;
}
else
{
userEncryptionTrustLevel = UserEncryptionTrustLevelWarning;
}
}
else
{
userEncryptionTrustLevel = UserEncryptionTrustLevelNone;
}
return userEncryptionTrustLevel;
}
#pragma mark -
- (MXPushRule*)getRoomPushRule

View file

@ -16,6 +16,17 @@
#import <MatrixKit/MatrixKit.h>
/**
RoomEncryptionTrustLevel represents the trust level in an encrypted room.
*/
typedef NS_ENUM(NSUInteger, RoomEncryptionTrustLevel) {
RoomEncryptionTrustLevelTrusted,
RoomEncryptionTrustLevelWarning,
RoomEncryptionTrustLevelNormal,
RoomEncryptionTrustLevelUnknown
};
/**
Define a `MXRoomSummary` category at Riot level.
*/
@ -32,4 +43,11 @@
*/
- (void)setRoomAvatarImageIn:(MXKImageView*)mxkImageView;
/**
Get the trust level in the room.
@return the trust level.
*/
- (RoomEncryptionTrustLevel)roomEncryptionTrustLevel;
@end

View file

@ -47,4 +47,34 @@
mxkImageView.contentMode = UIViewContentModeScaleAspectFill;
}
- (RoomEncryptionTrustLevel)roomEncryptionTrustLevel
{
RoomEncryptionTrustLevel roomEncryptionTrustLevel = RoomEncryptionTrustLevelUnknown;
if (self.trust)
{
double trustedUsersPercentage = self.trust.trustedUsersProgress.fractionCompleted;
double trustedDevicesPercentage = self.trust.trustedDevicesProgress.fractionCompleted;
if (trustedUsersPercentage >= 1.0)
{
if (trustedDevicesPercentage >= 1.0)
{
roomEncryptionTrustLevel = RoomEncryptionTrustLevelTrusted;
}
else
{
roomEncryptionTrustLevel = RoomEncryptionTrustLevelWarning;
}
}
else
{
roomEncryptionTrustLevel = RoomEncryptionTrustLevelNormal;
}
roomEncryptionTrustLevel = roomEncryptionTrustLevel;
}
return roomEncryptionTrustLevel;
}
@end

View file

@ -17,6 +17,7 @@
#import "MXSession+Riot.h"
#import "MXRoom+Riot.h"
#import "Riot-Swift.h"
@implementation MXSession (Riot)

View file

@ -18,7 +18,7 @@ import UIKit
extension UIStackView {
func vc_removeAllSubviews() {
func vc_removeAllArrangedSubviews() {
let subviews = self.arrangedSubviews
for subview in subviews {
self.removeArrangedSubview(subview)

View file

@ -19,7 +19,7 @@ import Foundation
extension UIView {
/// Add a subview matching parent view using autolayout
func vc_addSubViewMatchingParent(_ subView: UIView) {
@objc func vc_addSubViewMatchingParent(_ subView: UIView) {
self.addSubview(subView)
subView.translatesAutoresizingMaskIntoConstraints = false
let views = ["view": subView]
@ -31,4 +31,10 @@ extension UIView {
constraints.forEach { $0.isActive = true }
}
}
@objc func vc_removeAllSubviews() {
for subView in self.subviews {
subView.removeFromSuperview()
}
}
}

View file

@ -31,6 +31,7 @@ internal enum Asset {
internal static let riotIconCallkit = ImageAsset(name: "riot_icon_callkit")
internal static let adminIcon = ImageAsset(name: "admin_icon")
internal static let backIcon = ImageAsset(name: "back_icon")
internal static let camera = ImageAsset(name: "camera")
internal static let chevron = ImageAsset(name: "chevron")
internal static let closeButton = ImageAsset(name: "close_button")
internal static let disclosureIcon = ImageAsset(name: "disclosure_icon")
@ -50,6 +51,9 @@ internal enum Asset {
internal static let e2eBlocked = ImageAsset(name: "e2e_blocked")
internal static let e2eUnencrypted = ImageAsset(name: "e2e_unencrypted")
internal static let e2eWarning = ImageAsset(name: "e2e_warning")
internal static let encryptionNormal = ImageAsset(name: "encryption_normal")
internal static let encryptionTrusted = ImageAsset(name: "encryption_trusted")
internal static let encryptionWarning = ImageAsset(name: "encryption_warning")
internal static let directChatOff = ImageAsset(name: "directChatOff")
internal static let directChatOn = ImageAsset(name: "directChatOn")
internal static let favourite = ImageAsset(name: "favourite")
@ -64,6 +68,7 @@ internal enum Asset {
internal static let importFilesButton = ImageAsset(name: "import_files_button")
internal static let keyBackupLogo = ImageAsset(name: "key_backup_logo")
internal static let revealPasswordButton = ImageAsset(name: "reveal_password_button")
internal static let keyVerificationSuccessShield = ImageAsset(name: "key_verification_success_shield")
internal static let launchScreenRiot = ImageAsset(name: "LaunchScreenRiot")
internal static let cameraCapture = ImageAsset(name: "camera_capture")
internal static let cameraPlay = ImageAsset(name: "camera_play")

View file

@ -12,11 +12,6 @@ import UIKit
// swiftlint:disable explicit_type_interface identifier_name line_length type_body_length type_name
internal enum StoryboardScene {
internal enum DeviceVerificationDataLoadingViewController: StoryboardType {
internal static let storyboardName = "DeviceVerificationDataLoadingViewController"
internal static let initialScene = InitialSceneType<Riot.DeviceVerificationDataLoadingViewController>(storyboard: DeviceVerificationDataLoadingViewController.self)
}
internal enum DeviceVerificationIncomingViewController: StoryboardType {
internal static let storyboardName = "DeviceVerificationIncomingViewController"
@ -27,16 +22,6 @@ internal enum StoryboardScene {
internal static let initialScene = InitialSceneType<Riot.DeviceVerificationStartViewController>(storyboard: DeviceVerificationStartViewController.self)
}
internal enum DeviceVerificationVerifiedViewController: StoryboardType {
internal static let storyboardName = "DeviceVerificationVerifiedViewController"
internal static let initialScene = InitialSceneType<Riot.DeviceVerificationVerifiedViewController>(storyboard: DeviceVerificationVerifiedViewController.self)
}
internal enum DeviceVerificationVerifyViewController: StoryboardType {
internal static let storyboardName = "DeviceVerificationVerifyViewController"
internal static let initialScene = InitialSceneType<Riot.DeviceVerificationVerifyViewController>(storyboard: DeviceVerificationVerifyViewController.self)
}
internal enum EditHistoryViewController: StoryboardType {
internal static let storyboardName = "EditHistoryViewController"
@ -52,6 +37,11 @@ internal enum StoryboardScene {
internal static let initialScene = InitialSceneType<Riot.KeyBackupRecoverFromPassphraseViewController>(storyboard: KeyBackupRecoverFromPassphraseViewController.self)
}
internal enum KeyBackupRecoverFromPrivateKeyViewController: StoryboardType {
internal static let storyboardName = "KeyBackupRecoverFromPrivateKeyViewController"
internal static let initialScene = InitialSceneType<Riot.KeyBackupRecoverFromPrivateKeyViewController>(storyboard: KeyBackupRecoverFromPrivateKeyViewController.self)
}
internal enum KeyBackupRecoverFromRecoveryKeyViewController: StoryboardType {
internal static let storyboardName = "KeyBackupRecoverFromRecoveryKeyViewController"
@ -82,6 +72,46 @@ internal enum StoryboardScene {
internal static let initialScene = InitialSceneType<Riot.KeyBackupSetupSuccessFromRecoveryKeyViewController>(storyboard: KeyBackupSetupSuccessFromRecoveryKeyViewController.self)
}
internal enum KeyVerificationDataLoadingViewController: StoryboardType {
internal static let storyboardName = "KeyVerificationDataLoadingViewController"
internal static let initialScene = InitialSceneType<Riot.KeyVerificationDataLoadingViewController>(storyboard: KeyVerificationDataLoadingViewController.self)
}
internal enum KeyVerificationScanConfirmationViewController: StoryboardType {
internal static let storyboardName = "KeyVerificationScanConfirmationViewController"
internal static let initialScene = InitialSceneType<Riot.KeyVerificationScanConfirmationViewController>(storyboard: KeyVerificationScanConfirmationViewController.self)
}
internal enum KeyVerificationSelfVerifyStartViewController: StoryboardType {
internal static let storyboardName = "KeyVerificationSelfVerifyStartViewController"
internal static let initialScene = InitialSceneType<Riot.KeyVerificationSelfVerifyStartViewController>(storyboard: KeyVerificationSelfVerifyStartViewController.self)
}
internal enum KeyVerificationSelfVerifyWaitViewController: StoryboardType {
internal static let storyboardName = "KeyVerificationSelfVerifyWaitViewController"
internal static let initialScene = InitialSceneType<Riot.KeyVerificationSelfVerifyWaitViewController>(storyboard: KeyVerificationSelfVerifyWaitViewController.self)
}
internal enum KeyVerificationVerifiedViewController: StoryboardType {
internal static let storyboardName = "KeyVerificationVerifiedViewController"
internal static let initialScene = InitialSceneType<Riot.KeyVerificationVerifiedViewController>(storyboard: KeyVerificationVerifiedViewController.self)
}
internal enum KeyVerificationVerifyBySASViewController: StoryboardType {
internal static let storyboardName = "KeyVerificationVerifyBySASViewController"
internal static let initialScene = InitialSceneType<Riot.KeyVerificationVerifyBySASViewController>(storyboard: KeyVerificationVerifyBySASViewController.self)
}
internal enum KeyVerificationVerifyByScanningViewController: StoryboardType {
internal static let storyboardName = "KeyVerificationVerifyByScanningViewController"
internal static let initialScene = InitialSceneType<Riot.KeyVerificationVerifyByScanningViewController>(storyboard: KeyVerificationVerifyByScanningViewController.self)
}
internal enum QRCodeReaderViewController: StoryboardType {
internal static let storyboardName = "QRCodeReaderViewController"
internal static let initialScene = InitialSceneType<Riot.QRCodeReaderViewController>(storyboard: QRCodeReaderViewController.self)
}
internal enum ReactionHistoryViewController: StoryboardType {
internal static let storyboardName = "ReactionHistoryViewController"
@ -117,6 +147,21 @@ internal enum StoryboardScene {
internal static let initialScene = InitialSceneType<Riot.TemplateScreenViewController>(storyboard: TemplateScreenViewController.self)
}
internal enum UserVerificationSessionStatusViewController: StoryboardType {
internal static let storyboardName = "UserVerificationSessionStatusViewController"
internal static let initialScene = InitialSceneType<Riot.UserVerificationSessionStatusViewController>(storyboard: UserVerificationSessionStatusViewController.self)
}
internal enum UserVerificationSessionsStatusViewController: StoryboardType {
internal static let storyboardName = "UserVerificationSessionsStatusViewController"
internal static let initialScene = InitialSceneType<Riot.UserVerificationSessionsStatusViewController>(storyboard: UserVerificationSessionsStatusViewController.self)
}
internal enum UserVerificationStartViewController: StoryboardType {
internal static let storyboardName = "UserVerificationStartViewController"
internal static let initialScene = InitialSceneType<Riot.UserVerificationStartViewController>(storyboard: UserVerificationStartViewController.self)
}
internal enum WidgetPermissionViewController: StoryboardType {
internal static let storyboardName = "WidgetPermissionViewController"

View file

@ -226,7 +226,7 @@ internal enum VectorL10n {
internal static var authResetPasswordNextStepButton: String {
return VectorL10n.tr("Vector", "auth_reset_password_next_step_button")
}
/// Your password has been reset.\n\nYou have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, re-log in on each device.
/// Your password has been reset.\n\nYou have been logged out of all sessions and will no longer receive push notifications. To re-enable notifications, re-log in on each device.
internal static var authResetPasswordSuccessMessage: String {
return VectorL10n.tr("Vector", "auth_reset_password_success_message")
}
@ -362,7 +362,7 @@ internal enum VectorL10n {
internal static var callAlreadyDisplayed: String {
return VectorL10n.tr("Vector", "call_already_displayed")
}
/// Incoming video call...
/// Incoming video call
internal static var callIncomingVideo: String {
return VectorL10n.tr("Vector", "call_incoming_video")
}
@ -370,7 +370,7 @@ internal enum VectorL10n {
internal static func callIncomingVideoPrompt(_ p1: String) -> String {
return VectorL10n.tr("Vector", "call_incoming_video_prompt", p1)
}
/// Incoming call...
/// Incoming call
internal static var callIncomingVoice: String {
return VectorL10n.tr("Vector", "call_incoming_voice")
}
@ -778,15 +778,15 @@ internal enum VectorL10n {
internal static var deviceVerificationEmojiUnicorn: String {
return VectorL10n.tr("Vector", "device_verification_emoji_unicorn")
}
/// Cannot load device information.
/// Cannot load session information.
internal static var deviceVerificationErrorCannotLoadDevice: String {
return VectorL10n.tr("Vector", "device_verification_error_cannot_load_device")
}
/// Verify this device to mark it as trusted. Trusting devices of partners gives you extra peace of mind when using end-to-end encrypted messages.
/// Verify this session to mark it as trusted. Trusting sessions of partners gives you extra peace of mind when using end-to-end encrypted messages.
internal static var deviceVerificationIncomingDescription1: String {
return VectorL10n.tr("Vector", "device_verification_incoming_description_1")
}
/// Verifying this device will mark it as trusted, and also mark your device as trusted to the partner.
/// Verifying this session will mark it as trusted, and also mark your session as trusted to the partner.
internal static var deviceVerificationIncomingDescription2: String {
return VectorL10n.tr("Vector", "device_verification_incoming_description_2")
}
@ -798,6 +798,42 @@ internal enum VectorL10n {
internal static var deviceVerificationSecurityAdvice: String {
return VectorL10n.tr("Vector", "device_verification_security_advice")
}
/// This wasn't me
internal static var deviceVerificationSelfVerifyAlertCancelAction: String {
return VectorL10n.tr("Vector", "device_verification_self_verify_alert_cancel_action")
}
/// Use this session to verify your new one, granting it access to encrypted messages: %@\nIf you didnt sign in to this session, your account may be compromised.
internal static func deviceVerificationSelfVerifyAlertMessage(_ p1: String) -> String {
return VectorL10n.tr("Vector", "device_verification_self_verify_alert_message", p1)
}
/// New Sign In
internal static var deviceVerificationSelfVerifyAlertTitle: String {
return VectorL10n.tr("Vector", "device_verification_self_verify_alert_title")
}
/// Use this session to verify your new one, granting it access to encrypted messages.
internal static var deviceVerificationSelfVerifyStartInformation: String {
return VectorL10n.tr("Vector", "device_verification_self_verify_start_information")
}
/// Start verification
internal static var deviceVerificationSelfVerifyStartVerifyAction: String {
return VectorL10n.tr("Vector", "device_verification_self_verify_start_verify_action")
}
/// Waiting
internal static var deviceVerificationSelfVerifyStartWaiting: String {
return VectorL10n.tr("Vector", "device_verification_self_verify_start_waiting")
}
/// Use an existing session to verify this new one, granting it access to encrypted messages.
internal static var deviceVerificationSelfVerifyWaitInformation: String {
return VectorL10n.tr("Vector", "device_verification_self_verify_wait_information")
}
/// Complete security
internal static var deviceVerificationSelfVerifyWaitTitle: String {
return VectorL10n.tr("Vector", "device_verification_self_verify_wait_title")
}
/// Waiting
internal static var deviceVerificationSelfVerifyWaitWaiting: String {
return VectorL10n.tr("Vector", "device_verification_self_verify_wait_waiting")
}
/// Verify by comparing a short text string
internal static var deviceVerificationStartTitle: String {
return VectorL10n.tr("Vector", "device_verification_start_title")
@ -814,15 +850,15 @@ internal enum VectorL10n {
internal static var deviceVerificationStartVerifyButton: String {
return VectorL10n.tr("Vector", "device_verification_start_verify_button")
}
/// Waiting for partner to accept...
/// Waiting for partner to accept
internal static var deviceVerificationStartWaitPartner: String {
return VectorL10n.tr("Vector", "device_verification_start_wait_partner")
}
/// Verify device
/// Verify session
internal static var deviceVerificationTitle: String {
return VectorL10n.tr("Vector", "device_verification_title")
}
/// You've successfully verified this device.
/// You've successfully verified this session.
internal static var deviceVerificationVerifiedDescription1: String {
return VectorL10n.tr("Vector", "device_verification_verified_description_1")
}
@ -838,15 +874,15 @@ internal enum VectorL10n {
internal static var deviceVerificationVerifiedTitle: String {
return VectorL10n.tr("Vector", "device_verification_verified_title")
}
/// Verify this device by confirming the following emoji appear on the screen of the partner
/// Verify this session by confirming the following emoji appear on the screen of the partner
internal static var deviceVerificationVerifyTitleEmoji: String {
return VectorL10n.tr("Vector", "device_verification_verify_title_emoji")
}
/// Verify this device by confirming the following numbers appear on the screen of the partner
/// Verify this session by confirming the following numbers appear on the screen of the partner
internal static var deviceVerificationVerifyTitleNumber: String {
return VectorL10n.tr("Vector", "device_verification_verify_title_number")
}
/// Waiting for partner to confirm...
/// Waiting for partner to confirm
internal static var deviceVerificationVerifyWaitPartner: String {
return VectorL10n.tr("Vector", "device_verification_verify_wait_partner")
}
@ -926,7 +962,7 @@ internal enum VectorL10n {
internal static var e2eKeyBackupWrongVersionTitle: String {
return VectorL10n.tr("Vector", "e2e_key_backup_wrong_version_title")
}
/// You need to log back in to generate end-to-end encryption keys for this device and submit the public key to your homeserver.\nThis is a once off; sorry for the inconvenience.
/// You need to log back in to generate end-to-end encryption keys for this session and submit the public key to your homeserver.\nThis is a once off; sorry for the inconvenience.
internal static var e2eNeedLogInAgain: String {
return VectorL10n.tr("Vector", "e2e_need_log_in_again")
}
@ -934,11 +970,11 @@ internal enum VectorL10n {
internal static var e2eRoomKeyRequestIgnoreRequest: String {
return VectorL10n.tr("Vector", "e2e_room_key_request_ignore_request")
}
/// Your unverified device '%@' is requesting encryption keys.
/// Your unverified session '%@' is requesting encryption keys.
internal static func e2eRoomKeyRequestMessage(_ p1: String) -> String {
return VectorL10n.tr("Vector", "e2e_room_key_request_message", p1)
}
/// You added a new device '%@', which is requesting encryption keys.
/// You added a new session '%@', which is requesting encryption keys.
internal static func e2eRoomKeyRequestMessageNewDevice(_ p1: String) -> String {
return VectorL10n.tr("Vector", "e2e_room_key_request_message_new_device", p1)
}
@ -946,7 +982,7 @@ internal enum VectorL10n {
internal static var e2eRoomKeyRequestShareWithoutVerifying: String {
return VectorL10n.tr("Vector", "e2e_room_key_request_share_without_verifying")
}
/// Start verification...
/// Start verification
internal static var e2eRoomKeyRequestStartVerification: String {
return VectorL10n.tr("Vector", "e2e_room_key_request_start_verification")
}
@ -1030,7 +1066,7 @@ internal enum VectorL10n {
internal static var eventFormatterRerequestKeysPart1Link: String {
return VectorL10n.tr("Vector", "event_formatter_rerequest_keys_part1_link")
}
/// from your other devices.
/// from your other sessions.
internal static var eventFormatterRerequestKeysPart2: String {
return VectorL10n.tr("Vector", "event_formatter_rerequest_keys_part2")
}
@ -1258,7 +1294,7 @@ internal enum VectorL10n {
internal static var keyBackupRecoverBannerTitle: String {
return VectorL10n.tr("Vector", "key_backup_recover_banner_title")
}
/// Connect this device to Key Backup
/// Connect this session to Key Backup
internal static var keyBackupRecoverConnentBannerSubtitle: String {
return VectorL10n.tr("Vector", "key_backup_recover_connent_banner_subtitle")
}
@ -1294,6 +1330,10 @@ internal enum VectorL10n {
internal static var keyBackupRecoverFromPassphraseRecoverAction: String {
return VectorL10n.tr("Vector", "key_backup_recover_from_passphrase_recover_action")
}
/// Restoring backup
internal static var keyBackupRecoverFromPrivateKeyInfo: String {
return VectorL10n.tr("Vector", "key_backup_recover_from_private_key_info")
}
/// Use your recovery key to unlock your secure message history
internal static var keyBackupRecoverFromRecoveryKeyInfo: String {
return VectorL10n.tr("Vector", "key_backup_recover_from_recovery_key_info")
@ -1470,6 +1510,138 @@ internal enum VectorL10n {
internal static var keyBackupSetupTitle: String {
return VectorL10n.tr("Vector", "key_backup_setup_title")
}
/// You have to bootstrap cross-signing
internal static var keyVerificationBootstrapNotSetupMessage: String {
return VectorL10n.tr("Vector", "key_verification_bootstrap_not_setup_message")
}
/// Error
internal static var keyVerificationBootstrapNotSetupTitle: String {
return VectorL10n.tr("Vector", "key_verification_bootstrap_not_setup_title")
}
/// %@ wants to verify
internal static func keyVerificationIncomingRequestIncomingAlertMessage(_ p1: String) -> String {
return VectorL10n.tr("Vector", "key_verification_incoming_request_incoming_alert_message", p1)
}
/// Is the other device showing the same shield?
internal static var keyVerificationScanConfirmationScannedDeviceInformation: String {
return VectorL10n.tr("Vector", "key_verification_scan_confirmation_scanned_device_information")
}
/// Almost there!
internal static var keyVerificationScanConfirmationScannedTitle: String {
return VectorL10n.tr("Vector", "key_verification_scan_confirmation_scanned_title")
}
/// Is %@ showing the same shield?
internal static func keyVerificationScanConfirmationScannedUserInformation(_ p1: String) -> String {
return VectorL10n.tr("Vector", "key_verification_scan_confirmation_scanned_user_information", p1)
}
/// Waiting for other device
internal static var keyVerificationScanConfirmationScanningDeviceWaitingOther: String {
return VectorL10n.tr("Vector", "key_verification_scan_confirmation_scanning_device_waiting_other")
}
/// Almost there! Waiting for confirmation
internal static var keyVerificationScanConfirmationScanningTitle: String {
return VectorL10n.tr("Vector", "key_verification_scan_confirmation_scanning_title")
}
/// Waiting for %@
internal static func keyVerificationScanConfirmationScanningUserWaitingOther(_ p1: String) -> String {
return VectorL10n.tr("Vector", "key_verification_scan_confirmation_scanning_user_waiting_other", p1)
}
/// Verified
internal static var keyVerificationTileConclusionDoneTitle: String {
return VectorL10n.tr("Vector", "key_verification_tile_conclusion_done_title")
}
/// Unstrusted sign in
internal static var keyVerificationTileConclusionWarningTitle: String {
return VectorL10n.tr("Vector", "key_verification_tile_conclusion_warning_title")
}
/// Accept
internal static var keyVerificationTileRequestIncomingApprovalAccept: String {
return VectorL10n.tr("Vector", "key_verification_tile_request_incoming_approval_accept")
}
/// Decline
internal static var keyVerificationTileRequestIncomingApprovalDecline: String {
return VectorL10n.tr("Vector", "key_verification_tile_request_incoming_approval_decline")
}
/// Verification request
internal static var keyVerificationTileRequestIncomingTitle: String {
return VectorL10n.tr("Vector", "key_verification_tile_request_incoming_title")
}
/// Verification sent
internal static var keyVerificationTileRequestOutgoingTitle: String {
return VectorL10n.tr("Vector", "key_verification_tile_request_outgoing_title")
}
/// You accepted
internal static var keyVerificationTileRequestStatusAccepted: String {
return VectorL10n.tr("Vector", "key_verification_tile_request_status_accepted")
}
/// %@ cancelled
internal static func keyVerificationTileRequestStatusCancelled(_ p1: String) -> String {
return VectorL10n.tr("Vector", "key_verification_tile_request_status_cancelled", p1)
}
/// You cancelled
internal static var keyVerificationTileRequestStatusCancelledByMe: String {
return VectorL10n.tr("Vector", "key_verification_tile_request_status_cancelled_by_me")
}
/// Data loading
internal static var keyVerificationTileRequestStatusDataLoading: String {
return VectorL10n.tr("Vector", "key_verification_tile_request_status_data_loading")
}
/// Expired
internal static var keyVerificationTileRequestStatusExpired: String {
return VectorL10n.tr("Vector", "key_verification_tile_request_status_expired")
}
/// Waiting
internal static var keyVerificationTileRequestStatusWaiting: String {
return VectorL10n.tr("Vector", "key_verification_tile_request_status_waiting")
}
/// Verify user
internal static var keyVerificationUserTitle: String {
return VectorL10n.tr("Vector", "key_verification_user_title")
}
/// Youve successfully verified this user.
internal static var keyVerificationVerifiedUserDescription1: String {
return VectorL10n.tr("Vector", "key_verification_verified_user_description_1")
}
/// Messages with this user in this room are end-to-end encrypted and cant be read by third parties.
internal static var keyVerificationVerifiedUserDescription2: String {
return VectorL10n.tr("Vector", "key_verification_verified_user_description_2")
}
/// Can't scan?
internal static var keyVerificationVerifyQrCodeCannotScanAction: String {
return VectorL10n.tr("Vector", "key_verification_verify_qr_code_cannot_scan_action")
}
/// Scan the code to securely verify each other.
internal static var keyVerificationVerifyQrCodeInformation: String {
return VectorL10n.tr("Vector", "key_verification_verify_qr_code_information")
}
/// 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")
}
/// Scan their code
internal static var keyVerificationVerifyQrCodeScanCodeAction: String {
return VectorL10n.tr("Vector", "key_verification_verify_qr_code_scan_code_action")
}
/// QR code has been successfully validated.
internal static var keyVerificationVerifyQrCodeScanOtherCodeSuccessMessage: String {
return VectorL10n.tr("Vector", "key_verification_verify_qr_code_scan_other_code_success_message")
}
/// Code validated!
internal static var keyVerificationVerifyQrCodeScanOtherCodeSuccessTitle: String {
return VectorL10n.tr("Vector", "key_verification_verify_qr_code_scan_other_code_success_title")
}
/// Verify by scanning
internal static var keyVerificationVerifyQrCodeTitle: String {
return VectorL10n.tr("Vector", "key_verification_verify_qr_code_title")
}
/// Verify this user by confirming the following unique emoji appears on their screen, in the same order.
internal static var keyVerificationVerifyUserTitleEmoji: String {
return VectorL10n.tr("Vector", "key_verification_verify_user_title_emoji")
}
/// Verify this user by confirming the following numbers appear on their screen, in the same order.
internal static var keyVerificationVerifyUserTitleNumber: String {
return VectorL10n.tr("Vector", "key_verification_verify_user_title_number")
}
/// %.1fK
internal static func largeBadgeValueKFormat(_ p1: Float) -> String {
return VectorL10n.tr("Vector", "large_badge_value_k_format", p1)
@ -1482,6 +1654,30 @@ internal enum VectorL10n {
internal static var leave: String {
return VectorL10n.tr("Vector", "leave")
}
/// SESSION INFO
internal static var manageSessionInfo: String {
return VectorL10n.tr("Vector", "manage_session_info")
}
/// Session name
internal static var manageSessionName: String {
return VectorL10n.tr("Vector", "manage_session_name")
}
/// Not trusted
internal static var manageSessionNotTrusted: String {
return VectorL10n.tr("Vector", "manage_session_not_trusted")
}
/// Sign out of this session
internal static var manageSessionSignOut: String {
return VectorL10n.tr("Vector", "manage_session_sign_out")
}
/// Manage session
internal static var manageSessionTitle: String {
return VectorL10n.tr("Vector", "manage_session_title")
}
/// Trusted by you
internal static var manageSessionTrusted: String {
return VectorL10n.tr("Vector", "manage_session_trusted")
}
/// Library
internal static var mediaPickerLibrary: String {
return VectorL10n.tr("Vector", "media_picker_library")
@ -1594,7 +1790,7 @@ internal enum VectorL10n {
internal static var rename: String {
return VectorL10n.tr("Vector", "rename")
}
/// Please launch Riot on another device that can decrypt the message so it can send the keys to this device.
/// Please launch Riot on another device that can decrypt the message so it can send the keys to this session.
internal static var rerequestKeysAlertMessage: String {
return VectorL10n.tr("Vector", "rerequest_keys_alert_message")
}
@ -1766,7 +1962,7 @@ internal enum VectorL10n {
internal static var roomDetailsAddressesSection: String {
return VectorL10n.tr("Vector", "room_details_addresses_section")
}
/// Encrypt to verified devices only
/// Encrypt to verified sessions only
internal static var roomDetailsAdvancedE2eEncryptionBlacklistUnverifiedDevices: String {
return VectorL10n.tr("Vector", "room_details_advanced_e2e_encryption_blacklist_unverified_devices")
}
@ -2090,6 +2286,30 @@ internal enum VectorL10n {
internal static func roomManyUsersAreTyping(_ p1: String, _ p2: String) -> String {
return VectorL10n.tr("Vector", "room_many_users_are_typing", p1, p2)
}
/// Admin in %@
internal static func roomMemberPowerLevelAdminIn(_ p1: String) -> String {
return VectorL10n.tr("Vector", "room_member_power_level_admin_in", p1)
}
/// Custom (%@) in %@
internal static func roomMemberPowerLevelCustomIn(_ p1: String, _ p2: String) -> String {
return VectorL10n.tr("Vector", "room_member_power_level_custom_in", p1, p2)
}
/// Moderator in %@
internal static func roomMemberPowerLevelModeratorIn(_ p1: String) -> String {
return VectorL10n.tr("Vector", "room_member_power_level_moderator_in", p1)
}
/// Admin
internal static var roomMemberPowerLevelShortAdmin: String {
return VectorL10n.tr("Vector", "room_member_power_level_short_admin")
}
/// Custom
internal static var roomMemberPowerLevelShortCustom: String {
return VectorL10n.tr("Vector", "room_member_power_level_short_custom")
}
/// Mod
internal static var roomMemberPowerLevelShortModerator: String {
return VectorL10n.tr("Vector", "room_member_power_level_short_moderator")
}
/// Message edits
internal static var roomMessageEditsHistoryTitle: String {
return VectorL10n.tr("Vector", "room_message_edits_history_title")
@ -2170,7 +2390,7 @@ internal enum VectorL10n {
internal static var roomParticipantsActionSectionAdminTools: String {
return VectorL10n.tr("Vector", "room_participants_action_section_admin_tools")
}
/// Devices
/// Sessions
internal static var roomParticipantsActionSectionDevices: String {
return VectorL10n.tr("Vector", "room_participants_action_section_devices")
}
@ -2178,10 +2398,30 @@ internal enum VectorL10n {
internal static var roomParticipantsActionSectionDirectChats: String {
return VectorL10n.tr("Vector", "room_participants_action_section_direct_chats")
}
/// Other
/// Options
internal static var roomParticipantsActionSectionOther: String {
return VectorL10n.tr("Vector", "room_participants_action_section_other")
}
/// Security
internal static var roomParticipantsActionSectionSecurity: String {
return VectorL10n.tr("Vector", "room_participants_action_section_security")
}
/// Loading
internal static var roomParticipantsActionSecurityStatusLoading: String {
return VectorL10n.tr("Vector", "room_participants_action_security_status_loading")
}
/// Verified
internal static var roomParticipantsActionSecurityStatusVerified: String {
return VectorL10n.tr("Vector", "room_participants_action_security_status_verified")
}
/// Verify
internal static var roomParticipantsActionSecurityStatusVerify: String {
return VectorL10n.tr("Vector", "room_participants_action_security_status_verify")
}
/// Warning
internal static var roomParticipantsActionSecurityStatusWarning: String {
return VectorL10n.tr("Vector", "room_participants_action_security_status_warning")
}
/// Make admin
internal static var roomParticipantsActionSetAdmin: String {
return VectorL10n.tr("Vector", "room_participants_action_set_admin")
@ -2294,6 +2534,18 @@ internal enum VectorL10n {
internal static var roomParticipantsRemoveThirdPartyInvitePromptMsg: String {
return VectorL10n.tr("Vector", "room_participants_remove_third_party_invite_prompt_msg")
}
/// Messages in this room are end-to-end encrypted.\n\nYour messages are secured with locks and only you and the recipient have the unique keys to unlock them.
internal static var roomParticipantsSecurityInformationRoomEncrypted: String {
return VectorL10n.tr("Vector", "room_participants_security_information_room_encrypted")
}
/// Messages in this room are not end-to-end encrypted.
internal static var roomParticipantsSecurityInformationRoomNotEncrypted: String {
return VectorL10n.tr("Vector", "room_participants_security_information_room_not_encrypted")
}
/// Loading
internal static var roomParticipantsSecurityLoading: String {
return VectorL10n.tr("Vector", "room_participants_security_loading")
}
/// No identity server is configured so you cannot start a chat with a contact using an email.
internal static var roomParticipantsStartNewChatErrorUsingUserEmailWithoutIdentityServer: String {
return VectorL10n.tr("Vector", "room_participants_start_new_chat_error_using_user_email_without_identity_server")
@ -2470,7 +2722,7 @@ internal enum VectorL10n {
internal static func roomUnsentMessagesNotification(_ p1: String, _ p2: String) -> String {
return VectorL10n.tr("Vector", "room_unsent_messages_notification", p1, p2)
}
/// Message not sent due to unknown devices being present. %@ or %@ now?
/// Message not sent due to unknown sessions being present. %@ or %@ now?
internal static func roomUnsentMessagesUnknownDevicesNotification(_ p1: String, _ p2: String) -> String {
return VectorL10n.tr("Vector", "room_unsent_messages_unknown_devices_notification", p1, p2)
}
@ -2554,6 +2806,50 @@ internal enum VectorL10n {
internal static var searchRooms: String {
return VectorL10n.tr("Vector", "search_rooms")
}
/// ADVANCED
internal static var securitySettingsAdvanced: String {
return VectorL10n.tr("Vector", "security_settings_advanced")
}
/// MESSAGE BACKUP
internal static var securitySettingsBackup: String {
return VectorL10n.tr("Vector", "security_settings_backup")
}
/// Never send messages to untrusted sessions
internal static var securitySettingsBlacklistUnverifiedDevices: String {
return VectorL10n.tr("Vector", "security_settings_blacklist_unverified_devices")
}
/// Verify all of a users sessions to mark them as trusted and send messages to them.
internal static var securitySettingsBlacklistUnverifiedDevicesDescription: String {
return VectorL10n.tr("Vector", "security_settings_blacklist_unverified_devices_description")
}
/// CROSS-SIGNING
internal static var securitySettingsCrosssigning: String {
return VectorL10n.tr("Vector", "security_settings_crosssigning")
}
/// MY SESSIONS
internal static var securitySettingsCryptoSessions: String {
return VectorL10n.tr("Vector", "security_settings_crypto_sessions")
}
/// Trust sessions to grant access to end-to-end encrypted messages. If you dont recognise a session, change your login password and reset your Message Password used for Message Backup.
internal static var securitySettingsCryptoSessionsDescription: String {
return VectorL10n.tr("Vector", "security_settings_crypto_sessions_description")
}
/// Loading sessions
internal static var securitySettingsCryptoSessionsLoading: String {
return VectorL10n.tr("Vector", "security_settings_crypto_sessions_loading")
}
/// CRYPTOGRAPHY
internal static var securitySettingsCryptography: String {
return VectorL10n.tr("Vector", "security_settings_cryptography")
}
/// Export keys manually
internal static var securitySettingsExportKeysManually: String {
return VectorL10n.tr("Vector", "security_settings_export_keys_manually")
}
/// Security
internal static var securitySettingsTitle: String {
return VectorL10n.tr("Vector", "security_settings_title")
}
/// Send to %@
internal static func sendTo(_ p1: String) -> String {
return VectorL10n.tr("Vector", "send_to", p1)
@ -2694,19 +2990,19 @@ internal enum VectorL10n {
internal static var settingsCopyrightUrl: String {
return VectorL10n.tr("Vector", "settings_copyright_url")
}
/// Encrypt to verified devices only
/// Encrypt to verified sessions only
internal static var settingsCryptoBlacklistUnverifiedDevices: String {
return VectorL10n.tr("Vector", "settings_crypto_blacklist_unverified_devices")
}
/// \nDevice ID:
/// \nSession ID:
internal static var settingsCryptoDeviceId: String {
return VectorL10n.tr("Vector", "settings_crypto_device_id")
}
/// \nDevice key:\n
/// \nSession key:\n
internal static var settingsCryptoDeviceKey: String {
return VectorL10n.tr("Vector", "settings_crypto_device_key")
}
/// Device Public Name:
/// Session name:
internal static var settingsCryptoDeviceName: String {
return VectorL10n.tr("Vector", "settings_crypto_device_name")
}
@ -2726,11 +3022,11 @@ internal enum VectorL10n {
internal static var settingsDeactivateMyAccount: String {
return VectorL10n.tr("Vector", "settings_deactivate_my_account")
}
/// DEVICES
/// SESSIONS
internal static var settingsDevices: String {
return VectorL10n.tr("Vector", "settings_devices")
}
/// A device's public name is visible to people you communicate with
/// A session's public name is visible to people you communicate with
internal static var settingsDevicesDescription: String {
return VectorL10n.tr("Vector", "settings_devices_description")
}
@ -2874,7 +3170,7 @@ internal enum VectorL10n {
internal static var settingsKeyBackup: String {
return VectorL10n.tr("Vector", "settings_key_backup")
}
/// Connect this device to Key Backup
/// Connect this session to Key Backup
internal static var settingsKeyBackupButtonConnect: String {
return VectorL10n.tr("Vector", "settings_key_backup_button_connect")
}
@ -2906,19 +3202,19 @@ internal enum VectorL10n {
internal static func settingsKeyBackupInfoAlgorithm(_ p1: String) -> String {
return VectorL10n.tr("Vector", "settings_key_backup_info_algorithm", p1)
}
/// Checking...
/// Checking
internal static var settingsKeyBackupInfoChecking: String {
return VectorL10n.tr("Vector", "settings_key_backup_info_checking")
}
/// Your keys are not being backed up from this device.
/// Your keys are not being backed up from this session.
internal static var settingsKeyBackupInfoNone: String {
return VectorL10n.tr("Vector", "settings_key_backup_info_none")
}
/// This device is not backing up your keys, but you do have an existing backup you can restore from and add to going forward.
/// This session is not backing up your keys, but you do have an existing backup you can restore from and add to going forward.
internal static var settingsKeyBackupInfoNotValid: String {
return VectorL10n.tr("Vector", "settings_key_backup_info_not_valid")
}
/// Backing up %@ keys...
/// Backing up %@ keys
internal static func settingsKeyBackupInfoProgress(_ p1: String) -> String {
return VectorL10n.tr("Vector", "settings_key_backup_info_progress", p1)
}
@ -2926,7 +3222,7 @@ internal enum VectorL10n {
internal static var settingsKeyBackupInfoProgressDone: String {
return VectorL10n.tr("Vector", "settings_key_backup_info_progress_done")
}
/// Connect this device to key backup before signing out to avoid losing any keys that may only be on this device.
/// Connect this session to key backup before signing out to avoid losing any keys that may only be on this device.
internal static var settingsKeyBackupInfoSignoutWarning: String {
return VectorL10n.tr("Vector", "settings_key_backup_info_signout_warning")
}
@ -2938,11 +3234,11 @@ internal enum VectorL10n {
internal static func settingsKeyBackupInfoTrustSignatureInvalidDeviceVerified(_ p1: String) -> String {
return VectorL10n.tr("Vector", "settings_key_backup_info_trust_signature_invalid_device_verified", p1)
}
/// Backup has a signature from device with ID: %@
/// Backup has a signature from session with ID: %@
internal static func settingsKeyBackupInfoTrustSignatureUnknown(_ p1: String) -> String {
return VectorL10n.tr("Vector", "settings_key_backup_info_trust_signature_unknown", p1)
}
/// Backup has a valid signature from this device
/// Backup has a valid signature from this session
internal static var settingsKeyBackupInfoTrustSignatureValid: String {
return VectorL10n.tr("Vector", "settings_key_backup_info_trust_signature_valid")
}
@ -2954,7 +3250,7 @@ internal enum VectorL10n {
internal static func settingsKeyBackupInfoTrustSignatureValidDeviceVerified(_ p1: String) -> String {
return VectorL10n.tr("Vector", "settings_key_backup_info_trust_signature_valid_device_verified", p1)
}
/// This device is backing up your keys.
/// This session is backing up your keys.
internal static var settingsKeyBackupInfoValid: String {
return VectorL10n.tr("Vector", "settings_key_backup_info_valid")
}
@ -2970,14 +3266,6 @@ internal enum VectorL10n {
internal static var settingsLabsCreateConferenceWithJitsi: String {
return VectorL10n.tr("Vector", "settings_labs_create_conference_with_jitsi")
}
/// Cross-Signing
internal static var settingsLabsCrossSigning: String {
return VectorL10n.tr("Vector", "settings_labs_cross_signing")
}
/// Key verification by direct message
internal static var settingsLabsDmKeyVerification: String {
return VectorL10n.tr("Vector", "settings_labs_dm_key_verification")
}
/// End-to-End Encryption
internal static var settingsLabsE2eEncryption: String {
return VectorL10n.tr("Vector", "settings_labs_e2e_encryption")
@ -3074,6 +3362,10 @@ internal enum VectorL10n {
internal static var settingsReportBug: String {
return VectorL10n.tr("Vector", "settings_report_bug")
}
/// SECURITY
internal static var settingsSecurity: String {
return VectorL10n.tr("Vector", "settings_security")
}
/// Send anon crash & usage data
internal static var settingsSendCrashReport: String {
return VectorL10n.tr("Vector", "settings_send_crash_report")
@ -3230,6 +3522,10 @@ internal enum VectorL10n {
internal static var signOutNonExistingKeyBackupSignOutConfirmationAlertTitle: String {
return VectorL10n.tr("Vector", "sign_out_non_existing_key_backup_sign_out_confirmation_alert_title")
}
/// Skip
internal static var skip: String {
return VectorL10n.tr("Vector", "skip")
}
/// Start
internal static var start: String {
return VectorL10n.tr("Vector", "start")
@ -3266,11 +3562,11 @@ internal enum VectorL10n {
internal static var today: String {
return VectorL10n.tr("Vector", "today")
}
/// This room contains unknown devices which have not been verified.\nThis means there is no guarantee that the devices belong to the users they claim to.\nWe recommend you go through the verification process for each device before continuing, but you can resend the message without verifying if you prefer.
/// This room contains unknown sessions which have not been verified.\nThis means there is no guarantee that the sessions belong to the users they claim to.\nWe recommend you go through the verification process for each session before continuing, but you can resend the message without verifying if you prefer.
internal static var unknownDevicesAlert: String {
return VectorL10n.tr("Vector", "unknown_devices_alert")
}
/// Room contains unknown devices
/// Room contains unknown sessions
internal static var unknownDevicesAlertTitle: String {
return VectorL10n.tr("Vector", "unknown_devices_alert_title")
}
@ -3286,7 +3582,7 @@ internal enum VectorL10n {
internal static var unknownDevicesSendAnyway: String {
return VectorL10n.tr("Vector", "unknown_devices_send_anyway")
}
/// Unknown devices
/// Unknown sessions
internal static var unknownDevicesTitle: String {
return VectorL10n.tr("Vector", "unknown_devices_title")
}
@ -3294,6 +3590,98 @@ internal enum VectorL10n {
internal static var unknownDevicesVerify: String {
return VectorL10n.tr("Vector", "unknown_devices_verify")
}
/// If you didnt sign in to this session, your account may be compromised.
internal static var userVerificationSessionDetailsAdditionalInformationUntrustedCurrentUser: String {
return VectorL10n.tr("Vector", "user_verification_session_details_additional_information_untrusted_current_user")
}
/// Until this user trusts this session, messages sent to and from it are labelled with warnings. Alternatively, you can manually verify it.
internal static var userVerificationSessionDetailsAdditionalInformationUntrustedOtherUser: String {
return VectorL10n.tr("Vector", "user_verification_session_details_additional_information_untrusted_other_user")
}
/// This session is trusted for secure messaging because you verified it:
internal static var userVerificationSessionDetailsInformationTrustedCurrentUser: String {
return VectorL10n.tr("Vector", "user_verification_session_details_information_trusted_current_user")
}
/// This session is trusted for secure messaging because
internal static var userVerificationSessionDetailsInformationTrustedOtherUserPart1: String {
return VectorL10n.tr("Vector", "user_verification_session_details_information_trusted_other_user_part1")
}
/// verified it:
internal static var userVerificationSessionDetailsInformationTrustedOtherUserPart2: String {
return VectorL10n.tr("Vector", "user_verification_session_details_information_trusted_other_user_part2")
}
/// Verify this session to mark it as trusted & grant it access to encrypted messages:
internal static var userVerificationSessionDetailsInformationUntrustedCurrentUser: String {
return VectorL10n.tr("Vector", "user_verification_session_details_information_untrusted_current_user")
}
/// signed in using a new session:
internal static var userVerificationSessionDetailsInformationUntrustedOtherUser: String {
return VectorL10n.tr("Vector", "user_verification_session_details_information_untrusted_other_user")
}
/// Trusted
internal static var userVerificationSessionDetailsTrustedTitle: String {
return VectorL10n.tr("Vector", "user_verification_session_details_trusted_title")
}
/// Warning
internal static var userVerificationSessionDetailsUntrustedTitle: String {
return VectorL10n.tr("Vector", "user_verification_session_details_untrusted_title")
}
/// Verify
internal static var userVerificationSessionDetailsVerifyActionCurrentUser: String {
return VectorL10n.tr("Vector", "user_verification_session_details_verify_action_current_user")
}
/// Manually verify
internal static var userVerificationSessionDetailsVerifyActionOtherUser: String {
return VectorL10n.tr("Vector", "user_verification_session_details_verify_action_other_user")
}
/// Messages with this user in this room are end-to-end encrypted and cant be read by third parties.
internal static var userVerificationSessionsListInformation: String {
return VectorL10n.tr("Vector", "user_verification_sessions_list_information")
}
/// Trusted
internal static var userVerificationSessionsListSessionTrusted: String {
return VectorL10n.tr("Vector", "user_verification_sessions_list_session_trusted")
}
/// Not trusted
internal static var userVerificationSessionsListSessionUntrusted: String {
return VectorL10n.tr("Vector", "user_verification_sessions_list_session_untrusted")
}
/// Sessions
internal static var userVerificationSessionsListTableTitle: String {
return VectorL10n.tr("Vector", "user_verification_sessions_list_table_title")
}
/// Trusted
internal static var userVerificationSessionsListUserTrustLevelTrustedTitle: String {
return VectorL10n.tr("Vector", "user_verification_sessions_list_user_trust_level_trusted_title")
}
/// Unknown
internal static var userVerificationSessionsListUserTrustLevelUnknownTitle: String {
return VectorL10n.tr("Vector", "user_verification_sessions_list_user_trust_level_unknown_title")
}
/// Warning
internal static var userVerificationSessionsListUserTrustLevelWarningTitle: String {
return VectorL10n.tr("Vector", "user_verification_sessions_list_user_trust_level_warning_title")
}
/// To be secure, do this in person or use another way to communicate.
internal static var userVerificationStartAdditionalInformation: String {
return VectorL10n.tr("Vector", "user_verification_start_additional_information")
}
/// For extra security, verify
internal static var userVerificationStartInformationPart1: String {
return VectorL10n.tr("Vector", "user_verification_start_information_part1")
}
/// by checking a one-time code on both your devices.
internal static var userVerificationStartInformationPart2: String {
return VectorL10n.tr("Vector", "user_verification_start_information_part2")
}
/// Start verification
internal static var userVerificationStartVerifyAction: String {
return VectorL10n.tr("Vector", "user_verification_start_verify_action")
}
/// Waiting for %@
internal static func userVerificationStartWaitingPartner(_ p1: String) -> String {
return VectorL10n.tr("Vector", "user_verification_start_waiting_partner", p1)
}
/// Video
internal static var video: String {
return VectorL10n.tr("Vector", "video")
@ -3386,7 +3774,7 @@ internal enum VectorL10n {
internal static var widgetNoPowerToManage: String {
return VectorL10n.tr("Vector", "widget_no_power_to_manage")
}
/// Manage integrations...
/// Manage integrations
internal static var widgetPickerManageIntegrations: String {
return VectorL10n.tr("Vector", "widget_picker_manage_integrations")
}

View file

@ -56,7 +56,8 @@ final public class OnBoardingManager: NSObject {
case .success:
// Create DM room with Riot-bot
let httpOperation = self.session.createRoom(name: nil, visibility: .private, alias: nil, topic: nil, invite: [Constants.riotBotMatrixId], invite3PID: nil, isDirect: true, preset: .trustedPrivateChat) { (response) in
let roomCreationParameters = MXRoomCreationParameters(forDirectRoomWithUser: Constants.riotBotMatrixId)
let httpOperation = self.session.createRoom(parameters: roomCreationParameters) { (response) in
switch response {
case .success:

View file

@ -32,17 +32,9 @@ final class RiotSettings: NSObject {
static let pinRoomsWithUnreadMessages = "pinRoomsWithUnread"
static let allowStunServerFallback = "allowStunServerFallback"
static let stunServerFallback = "stunServerFallback"
static let enableCrossSigning = "enableCrossSigning"
static let enableDMKeyVerification = "enableDMKeyVerification"
}
/// Riot Standard Room Member Power Level
@objc
public enum RoomPowerLevel: Int {
case moderator = 50
case admin = 100
}
static let shared = RiotSettings()
// MARK: - Public
@ -123,22 +115,6 @@ final class RiotSettings: NSObject {
UserDefaults.standard.set(newValue, forKey: UserDefaultsKeys.createConferenceCallsWithJitsi)
}
}
var enableDMKeyVerification: Bool {
get {
return UserDefaults.standard.bool(forKey: UserDefaultsKeys.enableDMKeyVerification)
} set {
UserDefaults.standard.set(newValue, forKey: UserDefaultsKeys.enableDMKeyVerification)
}
}
var enableCrossSigning: Bool {
get {
return UserDefaults.standard.bool(forKey: UserDefaultsKeys.enableCrossSigning)
} set {
UserDefaults.standard.set(newValue, forKey: UserDefaultsKeys.enableCrossSigning)
}
}
// MARK: Calls

View file

@ -0,0 +1,44 @@
/*
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
/// Riot Standard Room Member Power Level
@objc
public enum RoomPowerLevel: Int {
case admin = 100
case moderator = 50
case user = 0
public init?(rawValue: Int) {
switch rawValue {
case 100...:
self = .admin
case 50...99:
self = .moderator
default:
self = .user
}
}
}
@objcMembers
public final class RoomPowerLevelHelper: NSObject {
static func roomPowerLevel(from rawValue: Int) -> RoomPowerLevel {
return RoomPowerLevel(rawValue: rawValue) ?? .user
}
}

View file

@ -62,6 +62,7 @@
@property (nonatomic) NSString *roomName;
@property (nonatomic, readonly) NSString *roomTopic;
@property (nonatomic, readonly) NSString *roomAvatarUrl;
@property (nonatomic, readonly) NSString *roomCanonicalAlias;
@property (nonatomic, readonly) NSArray<NSString*> *roomAliases;
@property (nonatomic, readonly) NSInteger numJoinedMembers; // -1 if unknown.

View file

@ -54,14 +54,22 @@
_roomName = publicRoom.displayname;
_roomAvatarUrl = publicRoom.avatarUrl;
_roomTopic = publicRoom.topic;
_roomCanonicalAlias = publicRoom.canonicalAlias;
_roomAliases = publicRoom.aliases;
_numJoinedMembers = publicRoom.numJoinedMembers;
// First try to fallback to the name if displayname isn't present
if (!_roomName.length) {
if (!_roomName.length)
{
_roomName = publicRoom.name;
}
if (!_roomName.length)
{
// Use the canonical alias if present.
_roomName = publicRoom.canonicalAlias;
}
if (!_roomName.length)
{
// Consider the room aliases to define a default room name.

View file

@ -25,7 +25,7 @@
#import "ForgotPasswordInputsView.h"
#import "AuthFallBackViewController.h"
@interface AuthenticationViewController () <AuthFallBackViewControllerDelegate>
@interface AuthenticationViewController () <AuthFallBackViewControllerDelegate, KeyVerificationCoordinatorBridgePresenterDelegate>
{
/**
Store the potential login error received by using a default homeserver different from matrix.org
@ -52,6 +52,7 @@
}
@property (nonatomic, readonly) BOOL isIdentityServerConfigured;
@property (nonatomic, strong) KeyVerificationCoordinatorBridgePresenter *keyVerificationCoordinatorBridgePresenter;
@end
@ -238,6 +239,11 @@
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if (self.keyVerificationCoordinatorBridgePresenter)
{
return;
}
// Verify that the app does not show the authentification screean whereas
// the user has already logged in.
@ -264,6 +270,7 @@
}
autoDiscovery = nil;
_keyVerificationCoordinatorBridgePresenter = nil;
}
- (BOOL)isIdentityServerConfigured
@ -423,6 +430,40 @@
}
}
- (void)presentCompleteSecurityWithSession:(MXSession*)session
{
KeyVerificationCoordinatorBridgePresenter *keyVerificationCoordinatorBridgePresenter = [[KeyVerificationCoordinatorBridgePresenter alloc] initWithSession:session];
keyVerificationCoordinatorBridgePresenter.delegate = self;
if (self.navigationController)
{
[keyVerificationCoordinatorBridgePresenter pushCompleteSecurityFrom:self.navigationController animated:YES];
}
else
{
[keyVerificationCoordinatorBridgePresenter presentCompleteSecurityFrom:self animated:YES];
}
self.keyVerificationCoordinatorBridgePresenter = keyVerificationCoordinatorBridgePresenter;
}
- (void)dismiss
{
self.userInteractionEnabled = YES;
[self.authenticationActivityIndicator stopAnimating];
// Remove auth view controller on successful login
if (self.navigationController)
{
// Pop the view controller
[self.navigationController popViewControllerAnimated:YES];
}
else
{
// Dismiss on successful login
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
}
#pragma mark - Fallback URL display
@ -1102,40 +1143,82 @@
- (void)authenticationViewController:(MXKAuthenticationViewController *)authenticationViewController didLogWithUserId:(NSString *)userId
{
self.userInteractionEnabled = NO;
[self.authenticationActivityIndicator startAnimating];
// Hide the custom server details in order to save customized inputs
[self hideCustomServers:YES];
MXKAccount *account = [[MXKAccountManager sharedManager] accountForUserId:userId];
MXSession *session = account.mxSession;
// Create DM with Riot-bot on new account creation.
if (self.authType == MXKAuthenticationTypeRegister)
{
MXKAccount *account = [[MXKAccountManager sharedManager] accountForUserId:userId];
[account.mxSession createRoom:nil
visibility:kMXRoomDirectoryVisibilityPrivate
roomAlias:nil
topic:nil
invite:@[@"@riot-bot:matrix.org"]
invite3PID:nil
isDirect:YES
preset:kMXRoomPresetTrustedPrivateChat
success:nil
failure:^(NSError *error) {
NSLog(@"[AuthenticationVC] Create chat with riot-bot failed");
}];
MXRoomCreationParameters *roomCreationParameters = [MXRoomCreationParameters parametersForDirectRoomWithUser:@"@riot-bot:matrix.org"];
[session createRoomWithParameters:roomCreationParameters success:nil failure:^(NSError *error) {
NSLog(@"[AuthenticationVC] Create chat with riot-bot failed");
}];
}
// Remove auth view controller on successful login
if (self.navigationController)
// Wait for session change to present complete security screen if needed
[self registerSessionStateChangeNotificationForSession:session];
}
- (void)registerSessionStateChangeNotificationForSession:(MXSession*)session
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sessionStateDidChangeNotification:) name:kMXSessionStateDidChangeNotification object:session];
}
- (void)unregisterSessionStateChangeNotification
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXSessionStateDidChangeNotification object:nil];
}
- (void)sessionStateDidChangeNotification:(NSNotification*)notification
{
MXSession *session = (MXSession*)notification.object;
if (session.state >= MXSessionStateStoreDataReady)
{
// Pop the view controller
[self.navigationController popViewControllerAnimated:YES];
}
else
{
// Dismiss on successful login
[self dismissViewControllerAnimated:YES completion:nil];
[self unregisterSessionStateChangeNotification];
if (session.crypto.crossSigning)
{
// Do not make key share requests while the "Complete security" is not complete.
// If the device is self-verified, the SDK will restore the existing key backup.
// Then, it will re-enable outgoing key share requests
[session.crypto setOutgoingKeyRequestsEnabled:NO onComplete:nil];
[session.crypto.crossSigning refreshStateWithSuccess:^(BOOL stateUpdated) {
if (session.crypto.crossSigning.state == MXCrossSigningStateCrossSigningExists)
{
dispatch_async(dispatch_get_main_queue(), ^{
self.userInteractionEnabled = YES;
[self.authenticationActivityIndicator stopAnimating];
[self presentCompleteSecurityWithSession:session];
});
}
else
{
[session.crypto setOutgoingKeyRequestsEnabled:YES onComplete:nil];
[self dismiss];
}
} failure:^(NSError * _Nonnull error) {
NSLog(@"[AuthenticationVC] Fail to refresh crypto state with error: %@", error);
dispatch_async(dispatch_get_main_queue(), ^{
[self dismiss];
});
}];
}
else
{
[self dismiss];
}
}
}
@ -1268,4 +1351,19 @@
[self hideCustomServers:NO];
}
#pragma mark - KeyVerificationCoordinatorBridgePresenterDelegate
- (void)keyVerificationCoordinatorBridgePresenterDelegateDidComplete:(KeyVerificationCoordinatorBridgePresenter * _Nonnull)coordinatorBridgePresenter otherUserId:(NSString * _Nonnull)otherUserId otherDeviceId:(NSString * _Nonnull)otherDeviceId
{
[self dismiss];
}
- (void)keyVerificationCoordinatorBridgePresenterDelegateDidCancel:(KeyVerificationCoordinatorBridgePresenter * _Nonnull)coordinatorBridgePresenter
{
// Set outgoing key requests back
[coordinatorBridgePresenter.session.crypto setOutgoingKeyRequestsEnabled:YES onComplete:nil];
[self dismiss];
}
@end

View file

@ -0,0 +1,61 @@
/*
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
final class CameraAccessAlertPresenter {
// MARK: - Public
func presentPermissionDeniedAlert(from presentingViewController: UIViewController, animated: Bool) {
guard let settingsURL = URL(string: UIApplication.openSettingsURLString) else {
return
}
let appDisplayName = Bundle.main.infoDictionary?["CFBundleDisplayName"] as? String ?? ""
let alert = UIAlertController(title: VectorL10n.camera, message: VectorL10n.cameraAccessNotGranted(appDisplayName), preferredStyle: .alert)
let cancelActionTitle = Bundle.mxk_localizedString(forKey: "ok")
let cancelAction = UIAlertAction(title: cancelActionTitle, style: .cancel, handler: { _ in
})
let settingsActionTitle = Bundle.mxk_localizedString(forKey: "settings")
let settingsAction = UIAlertAction(title: settingsActionTitle, style: .default, handler: { _ in
UIApplication.shared.open(settingsURL, options: [:], completionHandler: { (succeed) in
if !succeed {
print("[CameraPresenter] Fails to open settings")
}
})
})
alert.addAction(cancelAction)
alert.addAction(settingsAction)
presentingViewController.present(alert, animated: animated, completion: nil)
}
func presentCameraUnavailableAlert(from presentingViewController: UIViewController, animated: Bool) {
let alert = UIAlertController(title: VectorL10n.camera, message: VectorL10n.cameraUnavailable, preferredStyle: .alert)
let okAction = UIAlertAction(title: VectorL10n.accept, style: .default, handler: nil)
alert.addAction(okAction)
presentingViewController.present(alert, animated: true, completion: nil)
}
}

View file

@ -0,0 +1,61 @@
/*
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
/// CameraAccessManager handles camera availability and authorization.
final class CameraAccessManager {
// MARK: - Properties
var isCameraAvailable: Bool {
return UIImagePickerController.isSourceTypeAvailable(.camera)
}
var isCameraAccessGranted: Bool {
return AVCaptureDevice.authorizationStatus(for: .video) == .authorized
}
// MARK: - Public
func askAndRequestCameraAccessIfNeeded(completion: @escaping (_ granted: Bool) -> Void) {
let authorizationStatus = AVCaptureDevice.authorizationStatus(for: .video)
switch authorizationStatus {
case .authorized:
completion(true)
case .notDetermined:
self.requestCameraAccess(completion: { (granted) in
completion(granted)
})
case .denied, .restricted:
completion(false)
@unknown default:
break
}
}
// MARK: - Private
private func requestCameraAccess(completion: @escaping (_ granted: Bool) -> Void) {
AVCaptureDevice.requestAccess(for: .video) { granted in
DispatchQueue.main.async {
completion(granted)
}
}
}
}

View file

@ -35,16 +35,27 @@ import AVFoundation
// MARK: - Properties
// MARK: - Private
// MARK: Private
private let cameraAccessManager: CameraAccessManager
private let cameraAccessAlertPresenter: CameraAccessAlertPresenter
private weak var presentingViewController: UIViewController?
private weak var cameraViewController: UIViewController?
private var mediaUTIs: [MXKUTI] = []
// MARK: - Public
// MARK: Public
@objc weak var delegate: CameraPresenterDelegate?
// MARK: - Setup
override init() {
self.cameraAccessManager = CameraAccessManager()
self.cameraAccessAlertPresenter = CameraAccessAlertPresenter()
super.init()
}
// MARK: - Public
@objc func presentCamera(from presentingViewController: UIViewController, with mediaUTIs: [MXKUTI], animated: Bool) {
@ -63,24 +74,21 @@ import AVFoundation
// MARK: - Private
private func checkCameraPermissionAndPresentCamera(animated: Bool) {
guard let presentingViewController = self.presentingViewController else {
return
}
let authorizationStatus = AVCaptureDevice.authorizationStatus(for: .video)
guard self.cameraAccessManager.isCameraAvailable else {
self.cameraAccessAlertPresenter.presentCameraUnavailableAlert(from: presentingViewController, animated: animated)
return
}
switch authorizationStatus {
case .authorized:
self.presentCameraController(animated: animated)
case .notDetermined:
self.requestCameraAccess(completion: { (granted) in
if granted {
self.presentCameraController(animated: animated)
} else {
self.presentPermissionDeniedAlert()
}
})
case .denied, .restricted:
self.presentPermissionDeniedAlert()
@unknown default:
break
self.cameraAccessManager.askAndRequestCameraAccessIfNeeded { (granted) in
if granted {
self.presentCameraController(animated: animated)
} else {
self.cameraAccessAlertPresenter.presentPermissionDeniedAlert(from: presentingViewController, animated: animated)
}
}
}
@ -114,56 +122,6 @@ import AVFoundation
return imagePickerController
}
private func requestCameraAccess(completion: @escaping (_ granted: Bool) -> Void) {
AVCaptureDevice.requestAccess(for: .video) { granted in
DispatchQueue.main.async {
completion(granted)
}
}
}
private func presentPermissionDeniedAlert() {
guard let presentingViewController = self.presentingViewController, let settingsURL = URL(string: UIApplication.openSettingsURLString) else {
return
}
let appDisplayName = Bundle.main.infoDictionary?["CFBundleDisplayName"] as? String ?? ""
let alert = UIAlertController(title: VectorL10n.camera, message: VectorL10n.cameraAccessNotGranted(appDisplayName), preferredStyle: .alert)
let cancelActionTitle = Bundle.mxk_localizedString(forKey: "ok")
let cancelAction = UIAlertAction(title: cancelActionTitle, style: .cancel, handler: { _ in
})
let settingsActionTitle = Bundle.mxk_localizedString(forKey: "settings")
let settingsAction = UIAlertAction(title: settingsActionTitle, style: .default, handler: { _ in
UIApplication.shared.open(settingsURL, options: [:], completionHandler: { (succeed) in
if !succeed {
print("[CameraPresenter] Fails to open settings")
}
})
})
alert.addAction(cancelAction)
alert.addAction(settingsAction)
presentingViewController.present(alert, animated: true, completion: nil)
}
private func presentCameraUnavailableAlert() {
guard let presentingViewController = self.presentingViewController else {
return
}
let alert = UIAlertController(title: VectorL10n.camera, message: VectorL10n.cameraUnavailable, preferredStyle: .alert)
let okAction = UIAlertAction(title: VectorL10n.accept, style: .default, handler: nil)
alert.addAction(okAction)
presentingViewController.present(alert, animated: true, completion: nil)
}
}
// MARK: - UIImagePickerControllerDelegate

View file

@ -0,0 +1,95 @@
/*
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
final class CloseButton: UIButton, Themable {
// MARK: - Constants
private enum CircleBackgroundConstants {
static let height: CGFloat = 30.0
static let highlightedAlha: CGFloat = 0.5
static let normalAlha: CGFloat = 1.0
}
// MARK: - Properties
// MARK: Private
private var theme: Theme?
private var circleBackgroundView: UIView!
// MARK: Public
override var isHighlighted: Bool {
didSet {
self.circleBackgroundView.alpha = self.isHighlighted ? CircleBackgroundConstants.highlightedAlha : CircleBackgroundConstants.normalAlha
}
}
// MARK: - Life cycle
override func awakeFromNib() {
super.awakeFromNib()
self.backgroundColor = UIColor.clear
self.setImage(Asset.Images.closeButton.image, for: .normal)
self.setupCircleView()
self.update(theme: ThemeService.shared().theme)
}
override func layoutSubviews() {
super.layoutSubviews()
self.sendSubviewToBack(self.circleBackgroundView)
self.circleBackgroundView.layer.cornerRadius = self.circleBackgroundView.bounds.height/2
}
// MARK: - Private
private func setupCircleView() {
let rect = CGRect(x: 0, y: 0, width: CircleBackgroundConstants.height, height: CircleBackgroundConstants.height)
let view = UIView(frame: rect)
view.translatesAutoresizingMaskIntoConstraints = false
view.isUserInteractionEnabled = false
view.layer.masksToBounds = true
self.addSubview(view)
NSLayoutConstraint.activate([
view.heightAnchor.constraint(equalToConstant: CircleBackgroundConstants.height),
view.widthAnchor.constraint(equalTo: view.heightAnchor, multiplier: 1.0),
view.centerXAnchor.constraint(equalTo: self.centerXAnchor),
view.centerYAnchor.constraint(equalTo: self.centerYAnchor)
])
self.sendSubviewToBack(view)
self.circleBackgroundView = view
}
// MARK: - Themable
func update(theme: Theme) {
self.theme = theme
self.circleBackgroundView.backgroundColor = theme.headerTextSecondaryColor
}
}

View file

@ -240,6 +240,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou
break;
}
[self updateKeyBackupBanner];
[self forceRefresh];
}

View file

@ -137,7 +137,15 @@ static const CGFloat kDirectRoomBorderWidth = 3.0;
self.directRoomBorderView.hidden = !roomCellData.roomSummary.room.isDirect;
self.encryptedRoomIcon.hidden = !roomCellData.roomSummary.isEncrypted;
if (roomCellData.roomSummary.isEncrypted)
{
self.encryptedRoomIcon.hidden = NO;
self.encryptedRoomIcon.image = [self shieldImageForTrustLevel:roomCellData.roomSummary.roomEncryptionTrustLevel];
}
else
{
self.encryptedRoomIcon.hidden = YES;
}
[roomCellData.roomSummary setRoomAvatarImageIn:self.roomAvatar];
}
@ -153,4 +161,32 @@ static const CGFloat kDirectRoomBorderWidth = 3.0;
return 74;
}
- (UIImage*)shieldImageForTrustLevel:(RoomEncryptionTrustLevel)roomEncryptionTrustLevel
{
UIImage *shieldImage;
NSString *encryptionIconName;
switch (roomEncryptionTrustLevel)
{
case RoomEncryptionTrustLevelWarning:
encryptionIconName = @"encryption_warning";
break;
case RoomEncryptionTrustLevelNormal:
encryptionIconName = @"encryption_normal";
break;
case RoomEncryptionTrustLevelTrusted:
encryptionIconName = @"encryption_trusted";
break;
case RoomEncryptionTrustLevelUnknown:
encryptionIconName = @"encryption_normal";
break;
}
if (encryptionIconName)
{
shieldImage = [UIImage imageNamed:encryptionIconName];
}
return shieldImage;
}
@end

View file

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -75,10 +75,10 @@
<nil key="highlightedColor"/>
</label>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="OeZ-wN-eil">
<rect key="frame" x="524" y="14" width="0.0" height="20"/>
<rect key="frame" x="524" y="13.5" width="0.0" height="20"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mbn-A1-1Yw">
<rect key="frame" x="-4" y="2" width="9" height="17"/>
<rect key="frame" x="-4.5" y="1.5" width="9" height="17"/>
<accessibility key="accessibilityConfiguration" identifier="MissedNotifAndUnreadBadge"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="14"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@ -94,11 +94,11 @@
</constraints>
</view>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="e2e_verified" translatesAutoresizingMaskIntoConstraints="NO" id="NAZ-zd-MHS">
<rect key="frame" x="50" y="42" width="11" height="13"/>
<rect key="frame" x="44" y="43" width="16" height="16"/>
<accessibility key="accessibilityConfiguration" identifier="EncryptedRoomIcon"/>
<constraints>
<constraint firstAttribute="height" constant="13" id="QdE-73-LyZ"/>
<constraint firstAttribute="width" constant="11" id="i9u-Bs-pBy"/>
<constraint firstAttribute="height" constant="16" id="QdE-73-LyZ"/>
<constraint firstAttribute="width" constant="16" id="i9u-Bs-pBy"/>
</constraints>
</imageView>
</subviews>
@ -112,11 +112,11 @@
<constraint firstItem="dQt-mN-T6b" firstAttribute="leading" secondItem="RX5-eD-c3c" secondAttribute="trailing" constant="14" id="XFM-LG-4uJ"/>
<constraint firstItem="360-Go-RcG" firstAttribute="top" secondItem="aXz-IR-jj5" secondAttribute="top" constant="16" id="XyO-tl-6SX"/>
<constraint firstAttribute="trailing" secondItem="360-Go-RcG" secondAttribute="trailing" constant="10" id="YqC-WC-Wqe"/>
<constraint firstItem="NAZ-zd-MHS" firstAttribute="centerY" secondItem="dQt-mN-T6b" secondAttribute="centerY" id="c6L-cn-sJL"/>
<constraint firstItem="NAZ-zd-MHS" firstAttribute="centerY" secondItem="dQt-mN-T6b" secondAttribute="centerY" constant="2" id="c6L-cn-sJL"/>
<constraint firstItem="OeZ-wN-eil" firstAttribute="centerY" secondItem="360-Go-RcG" secondAttribute="centerY" id="fYc-th-Nay"/>
<constraint firstItem="dQt-mN-T6b" firstAttribute="top" secondItem="Lg1-xQ-AGn" secondAttribute="bottom" constant="4" id="iaT-57-GOs"/>
<constraint firstItem="RX5-eD-c3c" firstAttribute="top" secondItem="aXz-IR-jj5" secondAttribute="top" constant="15" id="mga-fG-I0L"/>
<constraint firstItem="NAZ-zd-MHS" firstAttribute="leading" secondItem="aXz-IR-jj5" secondAttribute="leading" constant="50" id="ofi-HP-uke"/>
<constraint firstItem="NAZ-zd-MHS" firstAttribute="leading" secondItem="aXz-IR-jj5" secondAttribute="leading" constant="44" id="ofi-HP-uke"/>
<constraint firstAttribute="trailing" secondItem="dQt-mN-T6b" secondAttribute="trailing" constant="10" id="t2m-pb-5zd"/>
<constraint firstItem="Lg1-xQ-AGn" firstAttribute="top" secondItem="aXz-IR-jj5" secondAttribute="top" constant="14" id="tY3-6V-A3B"/>
<constraint firstItem="RX5-eD-c3c" firstAttribute="leading" secondItem="aXz-IR-jj5" secondAttribute="leading" constant="13" id="tgy-cX-Wxm"/>

View file

@ -826,12 +826,15 @@
{
[participantCell render:contact];
// Update member badge
NSString *powerLevelText;
// Update power level label
if (contact.mxGroupUser.isPrivileged)
{
participantCell.thumbnailBadgeView.image = [UIImage imageNamed:@"admin_icon"];
participantCell.thumbnailBadgeView.hidden = NO;
powerLevelText = NSLocalizedStringFromTable(@"room_member_power_level_short_admin", @"Vector", nil);
}
participantCell.powerLevelLabel.text = powerLevelText;
}
cell = participantCell;

View file

@ -20,6 +20,7 @@
#import "AppDelegate.h"
#import "Riot-Swift.h"
#import "MXSession+Riot.h"
#import "RoomMemberTitleView.h"
@ -1040,37 +1041,52 @@
{
inviteArray = @[participantId];
}
MXWeakify(self);
void (^onFailure)(NSError *) = ^(NSError *error){
MXStrongifyAndReturnIfNil(self);
NSLog(@"[ContactDetailsViewController] Create room failed");
self->roomCreationRequest = nil;
[self removePendingActionMask];
// Notify user
[[AppDelegate theDelegate] showErrorAsAlert:error];
};
// Create a new room
roomCreationRequest = [self.mainSession createRoom:nil
visibility:kMXRoomDirectoryVisibilityPrivate
roomAlias:nil
topic:nil
invite:inviteArray
invite3PID:invite3PIDArray
isDirect:YES
preset:kMXRoomPresetTrustedPrivateChat
success:^(MXRoom *room) {
roomCreationRequest = nil;
[self removePendingActionMask];
[[AppDelegate theDelegate] showRoom:room.roomId andEventId:nil withMatrixSession:self.mainSession];
}
failure:^(NSError *error) {
NSLog(@"[ContactDetailsViewController] Create room failed");
roomCreationRequest = nil;
[self removePendingActionMask];
// Notify user
[[AppDelegate theDelegate] showErrorAsAlert:error];
}];
[self.mainSession canEnableE2EByDefaultInNewRoomWithUsers:inviteArray success:^(BOOL canEnableE2E) {
MXStrongifyAndReturnIfNil(self);
MXRoomCreationParameters *roomCreationParameters = [MXRoomCreationParameters new];
roomCreationParameters.visibility = kMXRoomDirectoryVisibilityPrivate;
roomCreationParameters.inviteArray = inviteArray;
roomCreationParameters.invite3PIDArray = invite3PIDArray;
roomCreationParameters.isDirect = YES;
roomCreationParameters.preset = kMXRoomPresetTrustedPrivateChat;
if (canEnableE2E && roomCreationParameters.invite3PIDArray == nil)
{
roomCreationParameters.initialStateEvents = @[
[MXRoomCreationParameters initialStateEventForEncryptionWithAlgorithm:kMXCryptoMegolmAlgorithm
]];
}
self->roomCreationRequest = [self.mainSession createRoomWithParameters:roomCreationParameters success:^(MXRoom *room) {
self->roomCreationRequest = nil;
[self removePendingActionMask];
[[AppDelegate theDelegate] showRoom:room.roomId andEventId:nil withMatrixSession:self.mainSession];
} failure:onFailure];
} failure:onFailure];
}
break;
}
@ -1093,36 +1109,28 @@
else
{
// Create a new room
roomCreationRequest = [self.mainSession createRoom:nil
visibility:kMXRoomDirectoryVisibilityPrivate
roomAlias:nil
topic:nil
invite:@[matrixId]
invite3PID:nil
isDirect:YES
preset:kMXRoomPresetTrustedPrivateChat
success:^(MXRoom *room) {
roomCreationRequest = nil;
// Delay the call in order to be sure that the room is ready
dispatch_async(dispatch_get_main_queue(), ^{
[room placeCallWithVideo:isVideoCall success:nil failure:nil];
[self removePendingActionMask];
});
} failure:^(NSError *error) {
NSLog(@"[ContactDetailsViewController] Create room failed");
roomCreationRequest = nil;
[self removePendingActionMask];
// Notify user
[[AppDelegate theDelegate] showErrorAsAlert:error];
}];
MXRoomCreationParameters *roomCreationParameters = [MXRoomCreationParameters parametersForDirectRoomWithUser:matrixId];
roomCreationRequest = [self.mainSession createRoomWithParameters:roomCreationParameters success:^(MXRoom *room) {
roomCreationRequest = nil;
// Delay the call in order to be sure that the room is ready
dispatch_async(dispatch_get_main_queue(), ^{
[room placeCallWithVideo:isVideoCall success:nil failure:nil];
[self removePendingActionMask];
});
} failure:^(NSError *error) {
NSLog(@"[ContactDetailsViewController] Create room failed");
roomCreationRequest = nil;
[self removePendingActionMask];
// Notify user
[[AppDelegate theDelegate] showErrorAsAlert:error];
}];
}
break;
}

View file

@ -1,13 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -57,14 +55,15 @@
</subviews>
<constraints>
<constraint firstItem="Lg1-xQ-AGn" firstAttribute="leading" secondItem="FfX-ul-Kr4" secondAttribute="trailing" constant="14" id="A6H-TC-2Pg"/>
<constraint firstAttribute="bottom" secondItem="FfX-ul-Kr4" secondAttribute="bottom" constant="15.5" id="D2o-qq-OsZ"/>
<constraint firstItem="O8i-B6-S6A" firstAttribute="centerY" secondItem="FfX-ul-Kr4" secondAttribute="centerY" id="L8U-Xi-rD7"/>
<constraint firstItem="Lg1-xQ-AGn" firstAttribute="centerY" secondItem="aXz-IR-jj5" secondAttribute="centerY" id="O6E-Di-2d4"/>
<constraint firstItem="apY-Nk-wQh" firstAttribute="top" secondItem="aXz-IR-jj5" secondAttribute="topMargin" constant="34" id="Rlm-bQ-Qpr"/>
<constraint firstItem="O8i-B6-S6A" firstAttribute="width" secondItem="FfX-ul-Kr4" secondAttribute="width" id="Sej-VT-sBx"/>
<constraint firstAttribute="trailingMargin" relation="greaterThanOrEqual" secondItem="Lg1-xQ-AGn" secondAttribute="trailing" constant="15" id="U1F-vo-7f6"/>
<constraint firstItem="apY-Nk-wQh" firstAttribute="leading" secondItem="aXz-IR-jj5" secondAttribute="leadingMargin" constant="42" id="dut-Df-DIU"/>
<constraint firstItem="FfX-ul-Kr4" firstAttribute="centerY" secondItem="aXz-IR-jj5" secondAttribute="centerY" id="gUw-GV-DPX"/>
<constraint firstItem="FfX-ul-Kr4" firstAttribute="leading" secondItem="aXz-IR-jj5" secondAttribute="leadingMargin" constant="6" id="qey-6T-URF"/>
<constraint firstItem="FfX-ul-Kr4" firstAttribute="top" secondItem="aXz-IR-jj5" secondAttribute="top" constant="16" id="wyT-JI-kQS"/>
<constraint firstItem="O8i-B6-S6A" firstAttribute="centerX" secondItem="FfX-ul-Kr4" secondAttribute="centerX" id="xfK-sI-YJQ"/>
</constraints>
</tableViewCellContentView>

View file

@ -28,11 +28,12 @@
MXKContact *contact;
}
@property (nonatomic) IBOutlet MXKImageView *thumbnailView;
@property (nonatomic) IBOutlet UIImageView *thumbnailBadgeView;
@property (nonatomic) IBOutlet UILabel *contactDisplayNameLabel;
@property (nonatomic) IBOutlet UILabel *contactInformationLabel;
@property (nonatomic) IBOutlet UIView *customAccessoryView;
@property (weak, nonatomic) IBOutlet MXKImageView *thumbnailView;
@property (weak, nonatomic) IBOutlet UILabel *contactDisplayNameLabel;
@property (weak, nonatomic) IBOutlet UILabel *powerLevelLabel;
@property (weak, nonatomic) IBOutlet UILabel *contactInformationLabel;
@property (weak, nonatomic) IBOutlet UIView *customAccessoryView;
@property (weak, nonatomic) IBOutlet UIImageView *avatarBadgeImageView;
@property (nonatomic) BOOL showCustomAccessoryView;

View file

@ -24,6 +24,7 @@
#import "AvatarGenerator.h"
#import "Tools.h"
#import "MXRoom+Riot.h"
#import "NBPhoneNumberUtil.h"
@ -55,6 +56,7 @@
// apply the vector colours
self.contactDisplayNameLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
self.contactInformationLabel.textColor = ThemeService.shared.theme.textSecondaryColor;
self.powerLevelLabel.textColor = ThemeService.shared.theme.textSecondaryColor;
// Clear the default background color of a MXKImageView instance
self.thumbnailView.defaultBackgroundColor = [UIColor clearColor];
@ -133,8 +135,6 @@
mxPresenceObserver = nil;
}
self.thumbnailBadgeView.hidden = YES;
// Sanity check: accept only object of MXKContact classes or sub-classes
NSParameterAssert([cellData isKindOfClass:[MXKContact class]]);
contact = (MXKContact*)cellData;
@ -146,6 +146,7 @@
self.thumbnailView.image = nil;
self.contactDisplayNameLabel.text = nil;
self.contactInformationLabel.text = nil;
self.powerLevelLabel.text = nil;
return;
}
@ -171,6 +172,7 @@
}];
[self refreshContactPresence];
[self refreshContactBadgeImage];
}
else
{
@ -234,6 +236,20 @@
self.thumbnailView.image = image;
}
- (void)refreshContactBadgeImage
{
NSString *matrixId = [self firstMatrixId];
UserEncryptionTrustLevel userEncryptionTrustLevel = UserEncryptionTrustLevelUnknown;
if (matrixId)
{
userEncryptionTrustLevel = [self.mxRoom encryptionTrustLevelForUserId:matrixId];
}
self.avatarBadgeImageView.image = [EncryptionTrustLevelBadgeImageHelper userBadgeImageFor:userEncryptionTrustLevel];
}
- (void)refreshContactDisplayName
{
self.contactDisplayNameLabel.text = contact.displayName;
@ -267,18 +283,7 @@
}
- (void)refreshLocalContactInformation
{
NSArray *identifiers = contact.matrixIdentifiers;
if (identifiers.count)
{
self.thumbnailBadgeView.image = [UIImage imageNamed:@"riot_icon"];
self.thumbnailBadgeView.hidden = NO;
}
else
{
self.thumbnailBadgeView.hidden = YES;
}
{
// Display the first contact method in sub label.
NSString *subLabelText = nil;
if (contact.emailAddresses.count)

View file

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -27,23 +27,28 @@
<constraint firstAttribute="height" constant="42" id="WPC-tL-hnM"/>
</constraints>
</view>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="e2Q-sr-Kz4">
<rect key="frame" x="42" y="10" width="20" height="21"/>
<accessibility key="accessibilityConfiguration" identifier="ThumbnailBadgeView"/>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Wg7-no-cax">
<rect key="frame" x="41" y="43" width="16" height="16"/>
<constraints>
<constraint firstAttribute="height" constant="21" id="5Do-zm-vSO"/>
<constraint firstAttribute="width" constant="20" id="IIL-0b-xCh"/>
<constraint firstAttribute="width" constant="16" id="Rcc-M1-2hb"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Display name" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Lg1-xQ-AGn" userLabel="member display name">
<rect key="frame" x="69" y="14" width="481" height="21"/>
<rect key="frame" x="69" y="14" width="489" height="21"/>
<accessibility key="accessibilityConfiguration" identifier="MemberDisplayName"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1nR-ck-5Xd">
<rect key="frame" x="563" y="24.5" width="0.0" height="0.0"/>
<accessibility key="accessibilityConfiguration" identifier="ContactInformationLabel"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<color key="textColor" red="0.66666666669999997" green="0.66666666669999997" blue="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="info label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dQt-mN-T6b">
<rect key="frame" x="69" y="39" width="531" height="20"/>
<rect key="frame" x="69" y="39" width="531" height="19.5"/>
<accessibility key="accessibilityConfiguration" identifier="ContactInformationLabel"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
<color key="textColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@ -62,16 +67,19 @@
<constraints>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="RX5-eD-c3c" secondAttribute="bottom" constant="15" id="0MH-4P-AYF"/>
<constraint firstAttribute="bottom" secondItem="dQt-mN-T6b" secondAttribute="bottom" constant="15" id="2cU-tU-nDT"/>
<constraint firstItem="e2Q-sr-Kz4" firstAttribute="trailing" secondItem="RX5-eD-c3c" secondAttribute="trailing" constant="7" id="Fib-p7-t8G"/>
<constraint firstItem="Lg1-xQ-AGn" firstAttribute="leading" secondItem="RX5-eD-c3c" secondAttribute="trailing" constant="14" id="Pgp-JM-oQd"/>
<constraint firstItem="dQt-mN-T6b" firstAttribute="leading" secondItem="RX5-eD-c3c" secondAttribute="trailing" constant="14" id="XFM-LG-4uJ"/>
<constraint firstItem="dQt-mN-T6b" firstAttribute="top" secondItem="Lg1-xQ-AGn" secondAttribute="bottom" constant="4" id="iaT-57-GOs"/>
<constraint firstItem="1nR-ck-5Xd" firstAttribute="centerY" secondItem="Lg1-xQ-AGn" secondAttribute="centerY" id="m01-Lq-3wa"/>
<constraint firstItem="RX5-eD-c3c" firstAttribute="top" secondItem="aXz-IR-jj5" secondAttribute="top" constant="15" id="mga-fG-I0L"/>
<constraint firstItem="Ogo-Qt-u2C" firstAttribute="leading" secondItem="Lg1-xQ-AGn" secondAttribute="trailing" constant="13" id="oNi-JM-zCJ"/>
<constraint firstItem="Ogo-Qt-u2C" firstAttribute="leading" secondItem="1nR-ck-5Xd" secondAttribute="trailing" id="nbn-Je-HEE"/>
<constraint firstItem="Wg7-no-cax" firstAttribute="bottom" secondItem="RX5-eD-c3c" secondAttribute="bottom" constant="2" id="pck-mZ-FjJ"/>
<constraint firstItem="Wg7-no-cax" firstAttribute="width" secondItem="Wg7-no-cax" secondAttribute="height" multiplier="1:1" id="sZo-F2-fpL"/>
<constraint firstAttribute="trailing" secondItem="dQt-mN-T6b" secondAttribute="trailing" id="t2m-pb-5zd"/>
<constraint firstItem="Lg1-xQ-AGn" firstAttribute="top" secondItem="aXz-IR-jj5" secondAttribute="top" constant="14" id="tY3-6V-A3B"/>
<constraint firstItem="1nR-ck-5Xd" firstAttribute="leading" secondItem="Lg1-xQ-AGn" secondAttribute="trailing" constant="5" id="tat-Fj-BSw"/>
<constraint firstItem="RX5-eD-c3c" firstAttribute="leading" secondItem="aXz-IR-jj5" secondAttribute="leading" constant="13" id="tgy-cX-Wxm"/>
<constraint firstItem="RX5-eD-c3c" firstAttribute="top" secondItem="e2Q-sr-Kz4" secondAttribute="top" constant="5" id="xrs-nE-h6t"/>
<constraint firstItem="Wg7-no-cax" firstAttribute="trailing" secondItem="RX5-eD-c3c" secondAttribute="trailing" constant="2" id="zT4-CH-fH8"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@ -81,14 +89,16 @@
<constraint firstAttribute="trailing" secondItem="Ogo-Qt-u2C" secondAttribute="trailing" constant="13" id="cWl-2f-cvI"/>
</constraints>
<connections>
<outlet property="avatarBadgeImageView" destination="Wg7-no-cax" id="mTr-4H-B6t"/>
<outlet property="contactDisplayNameLabel" destination="Lg1-xQ-AGn" id="xKB-Pw-12c"/>
<outlet property="contactInformationLabel" destination="dQt-mN-T6b" id="IKZ-wv-xVD"/>
<outlet property="customAccessViewWidthConstraint" destination="pDU-SS-0mb" id="A22-tz-iIz"/>
<outlet property="customAccessoryView" destination="Ogo-Qt-u2C" id="Hec-bO-0Av"/>
<outlet property="customAccessoryViewLeadingConstraint" destination="cWl-2f-cvI" id="WSj-ru-Qxx"/>
<outlet property="thumbnailBadgeView" destination="e2Q-sr-Kz4" id="kMn-et-a0z"/>
<outlet property="powerLevelLabel" destination="1nR-ck-5Xd" id="aIO-tg-fBq"/>
<outlet property="thumbnailView" destination="RX5-eD-c3c" id="GBi-K9-LhK"/>
</connections>
<point key="canvasLocation" x="80" y="48.575712143928037"/>
</tableViewCell>
</objects>
</document>

View file

@ -1,192 +0,0 @@
// File created from FlowTemplate
// $ createRootCoordinator.sh DeviceVerification DeviceVerification DeviceVerificationStart
/*
Copyright 2019 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
@objcMembers
final class DeviceVerificationCoordinator: DeviceVerificationCoordinatorType {
// MARK: - Properties
// MARK: Private
private let navigationRouter: NavigationRouterType
private let session: MXSession
private let otherUserId: String
private let otherDeviceId: String
private var incomingTransaction: MXIncomingSASTransaction?
// MARK: Public
// Must be used only internally
var childCoordinators: [Coordinator] = []
weak var delegate: DeviceVerificationCoordinatorDelegate?
// MARK: - Setup
/// Contrustor to start a verification of another device.
///
/// - Parameters:
/// - session: the MXSession
/// - otherUserId: the device user id
/// - otherDevice: the device id
init(session: MXSession, otherUserId: String, otherDeviceId: String) {
self.navigationRouter = NavigationRouter(navigationController: RiotNavigationController())
self.session = session
self.otherUserId = otherUserId
self.otherDeviceId = otherDeviceId
}
/// Contrustor to manage an incoming SAS device verification transaction
///
/// - Parameters:
/// - session: the MXSession
/// - transaction: an existing device verification transaction
convenience init(session: MXSession, incomingTransaction: MXIncomingSASTransaction) {
self.init(session: session,
otherUserId: incomingTransaction.otherUserId,
otherDeviceId: incomingTransaction.otherDeviceId)
self.incomingTransaction = incomingTransaction
}
// MARK: - Public methods
func start() {
let rootCoordinator = self.createDataLoadingScreenCoordinator()
rootCoordinator.start()
self.add(childCoordinator: rootCoordinator)
self.navigationRouter.setRootModule(rootCoordinator) { [weak self] in
self?.remove(childCoordinator: rootCoordinator)
}
}
func toPresentable() -> UIViewController {
return self.navigationRouter.toPresentable()
}
// MARK: - Private methods
private func createDataLoadingScreenCoordinator() -> DeviceVerificationDataLoadingCoordinator {
let coordinator = DeviceVerificationDataLoadingCoordinator(session: self.session, otherUserId: self.otherUserId, otherDeviceId: self.otherDeviceId)
coordinator.delegate = self
coordinator.start()
return coordinator
}
private func showStart(otherUser: MXUser, otherDevice: MXDeviceInfo) {
let coordinator = DeviceVerificationStartCoordinator(session: self.session, otherUser: otherUser, otherDevice: otherDevice)
coordinator.delegate = self
coordinator.start()
self.add(childCoordinator: coordinator)
self.navigationRouter.setRootModule(coordinator) { [weak self] in
self?.remove(childCoordinator: coordinator)
}
}
private func showIncoming(otherUser: MXUser, transaction: MXIncomingSASTransaction) {
let coordinator = DeviceVerificationIncomingCoordinator(session: self.session, otherUser: otherUser, transaction: transaction)
coordinator.delegate = self
coordinator.start()
self.add(childCoordinator: coordinator)
self.navigationRouter.setRootModule(coordinator) { [weak self] in
self?.remove(childCoordinator: coordinator)
}
}
private func showVerify(transaction: MXSASTransaction, animated: Bool) {
let coordinator = DeviceVerificationVerifyCoordinator(session: self.session, transaction: transaction)
coordinator.delegate = self
coordinator.start()
self.add(childCoordinator: coordinator)
self.navigationRouter.push(coordinator, animated: animated) { [weak self] in
self?.remove(childCoordinator: coordinator)
}
}
private func showVerified(animated: Bool) {
let viewController = DeviceVerificationVerifiedViewController.instantiate()
viewController.delegate = self
self.navigationRouter.setRootModule(viewController)
}
}
extension DeviceVerificationCoordinator: DeviceVerificationDataLoadingCoordinatorDelegate {
func deviceVerificationDataLoadingCoordinator(_ coordinator: DeviceVerificationDataLoadingCoordinatorType, didLoadUser user: MXUser, device: MXDeviceInfo) {
if let incomingTransaction = self.incomingTransaction {
self.showIncoming(otherUser: user, transaction: incomingTransaction)
} else {
self.showStart(otherUser: user, otherDevice: device)
}
}
func deviceVerificationDataLoadingCoordinatorDidCancel(_ coordinator: DeviceVerificationDataLoadingCoordinatorType) {
self.delegate?.deviceVerificationCoordinatorDidComplete(self, otherUserId: self.otherUserId, otherDeviceId: self.otherDeviceId)
}
}
extension DeviceVerificationCoordinator: DeviceVerificationStartCoordinatorDelegate {
func deviceVerificationStartCoordinator(_ coordinator: DeviceVerificationStartCoordinatorType, didCompleteWithOutgoingTransaction transaction: MXSASTransaction) {
self.showVerify(transaction: transaction, animated: true)
}
func deviceVerificationStartCoordinator(_ coordinator: DeviceVerificationStartCoordinatorType, didTransactionCancelled transaction: MXSASTransaction) {
self.delegate?.deviceVerificationCoordinatorDidComplete(self, otherUserId: self.otherUserId, otherDeviceId: self.otherDeviceId)
}
func deviceVerificationStartCoordinatorDidCancel(_ coordinator: DeviceVerificationStartCoordinatorType) {
self.delegate?.deviceVerificationCoordinatorDidComplete(self, otherUserId: self.otherUserId, otherDeviceId: self.otherDeviceId)
}
}
extension DeviceVerificationCoordinator: DeviceVerificationIncomingCoordinatorDelegate {
func deviceVerificationIncomingCoordinator(_ coordinator: DeviceVerificationIncomingCoordinatorType, didAcceptTransaction transaction: MXSASTransaction) {
self.showVerify(transaction: transaction, animated: true)
}
func deviceVerificationIncomingCoordinatorDidCancel(_ coordinator: DeviceVerificationIncomingCoordinatorType) {
self.delegate?.deviceVerificationCoordinatorDidComplete(self, otherUserId: self.otherUserId, otherDeviceId: self.otherDeviceId)
}
}
extension DeviceVerificationCoordinator: DeviceVerificationVerifyCoordinatorDelegate {
func deviceVerificationVerifyCoordinatorDidComplete(_ coordinator: DeviceVerificationVerifyCoordinatorType) {
self.showVerified(animated: true)
}
func deviceVerificationVerifyCoordinatorDidCancel(_ coordinator: DeviceVerificationVerifyCoordinatorType) {
self.delegate?.deviceVerificationCoordinatorDidComplete(self, otherUserId: self.otherUserId, otherDeviceId: self.otherDeviceId)
}
}
extension DeviceVerificationCoordinator: DeviceVerificationVerifiedViewControllerDelegate {
func deviceVerificationVerifiedViewControllerDidTapSetupAction(_ viewController: DeviceVerificationVerifiedViewController) {
self.delegate?.deviceVerificationCoordinatorDidComplete(self, otherUserId: self.otherUserId, otherDeviceId: self.otherDeviceId)
}
func deviceVerificationVerifiedViewControllerDidCancel(_ viewController: DeviceVerificationVerifiedViewController) {
self.delegate?.deviceVerificationCoordinatorDidComplete(self, otherUserId: self.otherUserId, otherDeviceId: self.otherDeviceId)
}
}

View file

@ -1,101 +0,0 @@
// File created from FlowTemplate
// $ createRootCoordinator.sh DeviceVerification DeviceVerification DeviceVerificationStart
/*
Copyright 2019 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
@objc protocol DeviceVerificationCoordinatorBridgePresenterDelegate {
func deviceVerificationCoordinatorBridgePresenterDelegateDidComplete(_ coordinatorBridgePresenter: DeviceVerificationCoordinatorBridgePresenter, otherUserId: String, otherDeviceId: String)
}
/// DeviceVerificationCoordinatorBridgePresenter enables to start DeviceVerificationCoordinator from a view controller.
/// This bridge is used while waiting for global usage of coordinator pattern.
@objcMembers
final class DeviceVerificationCoordinatorBridgePresenter: NSObject {
// MARK: - Properties
// MARK: Private
private let session: MXSession
private var coordinator: DeviceVerificationCoordinator?
// MARK: Public
weak var delegate: DeviceVerificationCoordinatorBridgePresenterDelegate?
// MARK: - Setup
init(session: MXSession) {
self.session = session
super.init()
}
// MARK: - Public
// NOTE: Default value feature is not compatible with Objective-C.
// func present(from viewController: UIViewController, animated: Bool) {
// self.present(from: viewController, animated: animated)
// }
func present(from viewController: UIViewController, otherUserId: String, otherDeviceId: String, animated: Bool) {
NSLog("[DeviceVerificationCoordinatorBridgePresenter] Present from \(viewController)")
let deviceVerificationCoordinator = DeviceVerificationCoordinator(session: self.session, otherUserId: otherUserId, otherDeviceId: otherDeviceId)
deviceVerificationCoordinator.delegate = self
viewController.present(deviceVerificationCoordinator.toPresentable(), animated: animated, completion: nil)
deviceVerificationCoordinator.start()
self.coordinator = deviceVerificationCoordinator
}
func present(from viewController: UIViewController, incomingTransaction: MXIncomingSASTransaction, animated: Bool) {
NSLog("[DeviceVerificationCoordinatorBridgePresenter] Present incoming verification from \(viewController)")
let deviceVerificationCoordinator = DeviceVerificationCoordinator(session: self.session, incomingTransaction: incomingTransaction)
deviceVerificationCoordinator.delegate = self
viewController.present(deviceVerificationCoordinator.toPresentable(), animated: animated, completion: nil)
deviceVerificationCoordinator.start()
self.coordinator = deviceVerificationCoordinator
}
func dismiss(animated: Bool, completion: (() -> Void)?) {
guard let coordinator = self.coordinator else {
return
}
NSLog("[DeviceVerificationCoordinatorBridgePresenter] Dismiss")
coordinator.toPresentable().dismiss(animated: animated) {
self.coordinator = nil
if let completion = completion {
completion()
}
}
}
}
// MARK: - DeviceVerificationCoordinatorDelegate
extension DeviceVerificationCoordinatorBridgePresenter: DeviceVerificationCoordinatorDelegate {
func deviceVerificationCoordinatorDidComplete(_ coordinator: DeviceVerificationCoordinatorType, otherUserId: String, otherDeviceId: String) {
self.delegate?.deviceVerificationCoordinatorBridgePresenterDelegateDidComplete(self, otherUserId: otherUserId, otherDeviceId: otherDeviceId)
}
}

View file

@ -1,70 +0,0 @@
// File created from ScreenTemplate
// $ createScreen.sh DeviceVerification/Loading DeviceVerificationDataLoading
/*
Copyright 2019 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 DeviceVerificationDataLoadingCoordinator: DeviceVerificationDataLoadingCoordinatorType {
// MARK: - Properties
// MARK: Private
private let session: MXSession
private var deviceVerificationDataLoadingViewModel: DeviceVerificationDataLoadingViewModelType
private let deviceVerificationDataLoadingViewController: DeviceVerificationDataLoadingViewController
// MARK: Public
// Must be used only internally
var childCoordinators: [Coordinator] = []
weak var delegate: DeviceVerificationDataLoadingCoordinatorDelegate?
// MARK: - Setup
init(session: MXSession, otherUserId: String, otherDeviceId: String) {
self.session = session
let deviceVerificationDataLoadingViewModel = DeviceVerificationDataLoadingViewModel(session: self.session, otherUserId: otherUserId, otherDeviceId: otherDeviceId)
let deviceVerificationDataLoadingViewController = DeviceVerificationDataLoadingViewController.instantiate(with: deviceVerificationDataLoadingViewModel)
self.deviceVerificationDataLoadingViewModel = deviceVerificationDataLoadingViewModel
self.deviceVerificationDataLoadingViewController = deviceVerificationDataLoadingViewController
}
// MARK: - Public methods
func start() {
self.deviceVerificationDataLoadingViewModel.coordinatorDelegate = self
}
func toPresentable() -> UIViewController {
return self.deviceVerificationDataLoadingViewController
}
}
// MARK: - DeviceVerificationDataLoadingViewModelCoordinatorDelegate
extension DeviceVerificationDataLoadingCoordinator: DeviceVerificationDataLoadingViewModelCoordinatorDelegate {
func deviceVerificationDataLoadingViewModel(_ viewModel: DeviceVerificationDataLoadingViewModelType, didLoadUser user: MXUser, device: MXDeviceInfo) {
self.delegate?.deviceVerificationDataLoadingCoordinator(self, didLoadUser: user, device: device)
}
func deviceVerificationDataLoadingViewModelDidCancel(_ viewModel: DeviceVerificationDataLoadingViewModelType) {
self.delegate?.deviceVerificationDataLoadingCoordinatorDidCancel(self)
}
}

View file

@ -1,105 +0,0 @@
// File created from ScreenTemplate
// $ createScreen.sh DeviceVerification/Loading DeviceVerificationDataLoading
/*
Copyright 2019 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 DeviceVerificationDataLoadingViewModelError: Error {
case unknown
}
final class DeviceVerificationDataLoadingViewModel: DeviceVerificationDataLoadingViewModelType {
// MARK: - Properties
// MARK: Private
private let session: MXSession
private let otherUserId: String
private let otherDeviceId: String
// MARK: Public
weak var viewDelegate: DeviceVerificationDataLoadingViewModelViewDelegate?
weak var coordinatorDelegate: DeviceVerificationDataLoadingViewModelCoordinatorDelegate?
// MARK: - Setup
init(session: MXSession, otherUserId: String, otherDeviceId: String) {
self.session = session
self.otherUserId = otherUserId
self.otherDeviceId = otherDeviceId
}
deinit {
}
// MARK: - Public
func process(viewAction: DeviceVerificationDataLoadingViewAction) {
switch viewAction {
case .loadData:
self.loadData()
case .cancel:
self.coordinatorDelegate?.deviceVerificationDataLoadingViewModelDidCancel(self)
}
}
// MARK: - Private
private func loadData() {
guard let crypto = self.session.crypto else {
self.update(viewState: .errorMessage(VectorL10n.deviceVerificationErrorCannotLoadDevice))
NSLog("[DeviceVerificationDataLoadingViewModel] Error session.crypto is nil")
return
}
if let otherUser = self.session.user(withUserId: otherUserId) {
self.update(viewState: .loading)
crypto.downloadKeys([self.otherUserId], forceDownload: false, success: { [weak self] (usersDevicesMap) in
guard let sself = self else {
return
}
if let otherDevice = usersDevicesMap?.object(forDevice: sself.otherDeviceId, forUser: sself.otherUserId) {
sself.update(viewState: .loaded)
sself.coordinatorDelegate?.deviceVerificationDataLoadingViewModel(sself, didLoadUser: otherUser, device: otherDevice)
} else {
sself.update(viewState: .errorMessage(VectorL10n.deviceVerificationErrorCannotLoadDevice))
}
}, failure: { [weak self] (error) in
guard let sself = self else {
return
}
let finalError = error ?? DeviceVerificationDataLoadingViewModelError.unknown
sself.update(viewState: .error(finalError))
})
} else {
self.update(viewState: .errorMessage(VectorL10n.deviceVerificationErrorCannotLoadDevice))
}
}
private func update(viewState: DeviceVerificationDataLoadingViewState) {
self.viewDelegate?.deviceVerificationDataLoadingViewModel(self, didUpdateViewState: viewState)
}
}

View file

@ -1,37 +0,0 @@
// File created from ScreenTemplate
// $ createScreen.sh DeviceVerification/Loading DeviceVerificationDataLoading
/*
Copyright 2019 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 DeviceVerificationDataLoadingViewModelViewDelegate: class {
func deviceVerificationDataLoadingViewModel(_ viewModel: DeviceVerificationDataLoadingViewModelType, didUpdateViewState viewSate: DeviceVerificationDataLoadingViewState)
}
protocol DeviceVerificationDataLoadingViewModelCoordinatorDelegate: class {
func deviceVerificationDataLoadingViewModel(_ viewModel: DeviceVerificationDataLoadingViewModelType, didLoadUser user: MXUser, device: MXDeviceInfo)
func deviceVerificationDataLoadingViewModelDidCancel(_ viewModel: DeviceVerificationDataLoadingViewModelType)
}
/// Protocol describing the view model used by `DeviceVerificationDataLoadingViewController`
protocol DeviceVerificationDataLoadingViewModelType {
var viewDelegate: DeviceVerificationDataLoadingViewModelViewDelegate? { get set }
var coordinatorDelegate: DeviceVerificationDataLoadingViewModelCoordinatorDelegate? { get set }
func process(viewAction: DeviceVerificationDataLoadingViewAction)
}

View file

@ -1,71 +0,0 @@
// File created from ScreenTemplate
// $ createScreen.sh DeviceVerification/Verify DeviceVerificationVerify
/*
Copyright 2019 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 DeviceVerificationVerifyCoordinator: DeviceVerificationVerifyCoordinatorType {
// MARK: - Properties
// MARK: Private
private let session: MXSession
private var deviceVerificationVerifyViewModel: DeviceVerificationVerifyViewModelType
private let deviceVerificationVerifyViewController: DeviceVerificationVerifyViewController
// MARK: Public
// Must be used only internally
var childCoordinators: [Coordinator] = []
weak var delegate: DeviceVerificationVerifyCoordinatorDelegate?
// MARK: - Setup
init(session: MXSession, transaction: MXSASTransaction) {
self.session = session
let deviceVerificationVerifyViewModel = DeviceVerificationVerifyViewModel(session: self.session, transaction: transaction)
let deviceVerificationVerifyViewController = DeviceVerificationVerifyViewController.instantiate(with: deviceVerificationVerifyViewModel)
self.deviceVerificationVerifyViewModel = deviceVerificationVerifyViewModel
self.deviceVerificationVerifyViewController = deviceVerificationVerifyViewController
}
// MARK: - Public methods
func start() {
self.deviceVerificationVerifyViewModel.coordinatorDelegate = self
}
func toPresentable() -> UIViewController {
return self.deviceVerificationVerifyViewController
}
}
// MARK: - DeviceVerificationVerifyViewModelCoordinatorDelegate
extension DeviceVerificationVerifyCoordinator: DeviceVerificationVerifyViewModelCoordinatorDelegate {
func deviceVerificationVerifyViewModelDidComplete(_ viewModel: DeviceVerificationVerifyViewModelType) {
self.delegate?.deviceVerificationVerifyCoordinatorDidComplete(self)
}
func deviceVerificationVerifyViewModelDidCancel(_ viewModel: DeviceVerificationVerifyViewModelType) {
self.delegate?.deviceVerificationVerifyCoordinatorDidCancel(self)
}
}

View file

@ -1,40 +0,0 @@
// File created from ScreenTemplate
// $ createScreen.sh DeviceVerification/Verify DeviceVerificationVerify
/*
Copyright 2019 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 DeviceVerificationVerifyViewModelViewDelegate: class {
func deviceVerificationVerifyViewModel(_ viewModel: DeviceVerificationVerifyViewModelType, didUpdateViewState viewSate: DeviceVerificationVerifyViewState)
}
protocol DeviceVerificationVerifyViewModelCoordinatorDelegate: class {
func deviceVerificationVerifyViewModelDidComplete(_ viewModel: DeviceVerificationVerifyViewModelType)
func deviceVerificationVerifyViewModelDidCancel(_ viewModel: DeviceVerificationVerifyViewModelType)
}
/// Protocol describing the view model used by `DeviceVerificationVerifyViewController`
protocol DeviceVerificationVerifyViewModelType {
var viewDelegate: DeviceVerificationVerifyViewModelViewDelegate? { get set }
var coordinatorDelegate: DeviceVerificationVerifyViewModelCoordinatorDelegate? { get set }
func process(viewAction: DeviceVerificationVerifyViewAction)
var emojis: [MXEmojiRepresentation]? { get set }
var decimal: String? { get set }
}

View file

@ -22,9 +22,9 @@
#import "AppDelegate.h"
@interface EncryptionInfoView() <DeviceVerificationCoordinatorBridgePresenterDelegate>
@interface EncryptionInfoView() <KeyVerificationCoordinatorBridgePresenterDelegate>
{
DeviceVerificationCoordinatorBridgePresenter *deviceVerificationCoordinatorBridgePresenter;
KeyVerificationCoordinatorBridgePresenter *keyVerificationCoordinatorBridgePresenter;
}
@end
@ -54,16 +54,16 @@
- (void)onButtonPressed:(id)sender
{
UIViewController *rootViewController = [AppDelegate theDelegate].window.rootViewController;
if (sender == self.verifyButton && self.mxDeviceInfo.verified != MXDeviceVerified
if (sender == self.verifyButton && self.mxDeviceInfo.trustLevel.localVerificationStatus != MXDeviceVerified
&& self.mxDeviceInfo
&& rootViewController)
{
// Redirect to the interactive device verification flow
deviceVerificationCoordinatorBridgePresenter = [[DeviceVerificationCoordinatorBridgePresenter alloc] initWithSession:self.mxSession];
deviceVerificationCoordinatorBridgePresenter.delegate = self;
keyVerificationCoordinatorBridgePresenter = [[KeyVerificationCoordinatorBridgePresenter alloc] initWithSession:self.mxSession];
keyVerificationCoordinatorBridgePresenter.delegate = self;
// Show it on the root view controller
[deviceVerificationCoordinatorBridgePresenter presentFrom:rootViewController otherUserId:self.mxDeviceInfo.userId otherDeviceId:self.mxDeviceInfo.deviceId animated:YES];
[keyVerificationCoordinatorBridgePresenter presentFrom:rootViewController otherUserId:self.mxDeviceInfo.userId otherDeviceId:self.mxDeviceInfo.deviceId animated:YES];
}
else
{
@ -71,11 +71,21 @@
}
}
- (void)deviceVerificationCoordinatorBridgePresenterDelegateDidComplete:(DeviceVerificationCoordinatorBridgePresenter * _Nonnull)coordinatorBridgePresenter otherUserId:(NSString * _Nonnull)otherUserId otherDeviceId:(NSString * _Nonnull)otherDeviceId {
- (void)keyVerificationCoordinatorBridgePresenterDelegateDidComplete:(KeyVerificationCoordinatorBridgePresenter * _Nonnull)coordinatorBridgePresenter otherUserId:(NSString * _Nonnull)otherUserId otherDeviceId:(NSString * _Nonnull)otherDeviceId
{
[self dismissKeyVerificationCoordinatorBridgePresenter];
}
[deviceVerificationCoordinatorBridgePresenter dismissWithAnimated:YES completion:nil];
deviceVerificationCoordinatorBridgePresenter = nil;
- (void)keyVerificationCoordinatorBridgePresenterDelegateDidCancel:(KeyVerificationCoordinatorBridgePresenter * _Nonnull)coordinatorBridgePresenter
{
[self dismissKeyVerificationCoordinatorBridgePresenter];
}
- (void)dismissKeyVerificationCoordinatorBridgePresenter
{
[keyVerificationCoordinatorBridgePresenter dismissWithAnimated:YES completion:nil];
keyVerificationCoordinatorBridgePresenter = nil;
// Eject like MXKEncryptionInfoView does
[self removeFromSuperview];
}

View file

@ -159,7 +159,15 @@ static const CGFloat kDirectRoomBorderWidth = 3.0;
self.directRoomBorderView.hidden = !roomCellData.roomSummary.room.isDirect;
self.encryptedRoomIcon.hidden = !roomCellData.roomSummary.isEncrypted;
if (roomCellData.roomSummary.isEncrypted)
{
self.encryptedRoomIcon.hidden = NO;
self.encryptedRoomIcon.image = [EncryptionTrustLevelBadgeImageHelper roomBadgeImageFor:roomCellData.roomSummary.roomEncryptionTrustLevel];
}
else
{
self.encryptedRoomIcon.hidden = YES;
}
[roomCellData.roomSummary setRoomAvatarImageIn:self.roomAvatar];
}

View file

@ -1,12 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -39,7 +38,7 @@
<rect key="frame" x="80" y="5" width="0.0" height="20"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ZUZ-tv-dVV">
<rect key="frame" x="-4" y="2" width="9" height="17"/>
<rect key="frame" x="-4.5" y="1.5" width="9" height="17"/>
<accessibility key="accessibilityConfiguration" identifier="MissedNotifAndUnreadBadge"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="14"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@ -54,11 +53,11 @@
<constraint firstItem="ZUZ-tv-dVV" firstAttribute="centerX" secondItem="Q6g-b0-3sZ" secondAttribute="centerX" id="km0-Wj-nJ0"/>
</constraints>
</view>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="e2e_verified" translatesAutoresizingMaskIntoConstraints="NO" id="5Yd-df-HbB">
<rect key="frame" x="53" y="55" width="15" height="18"/>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="encryption_normal" translatesAutoresizingMaskIntoConstraints="NO" id="5Yd-df-HbB">
<rect key="frame" x="51" y="52" width="21" height="20"/>
<constraints>
<constraint firstAttribute="height" constant="18" id="UEZ-5S-KMf"/>
<constraint firstAttribute="width" constant="15" id="bbS-D2-SZi"/>
<constraint firstAttribute="height" constant="20" id="OSj-Tf-ZuJ"/>
<constraint firstAttribute="width" secondItem="5Yd-df-HbB" secondAttribute="height" multiplier="1:1" constant="1" id="QGp-OT-7yA"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="RoomTitle" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="oxX-IL-dG4">
@ -93,7 +92,6 @@
</subviews>
</view>
<constraints>
<constraint firstAttribute="trailing" secondItem="5Yd-df-HbB" secondAttribute="trailing" constant="12" id="0gr-xn-dfD"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="oxX-IL-dG4" secondAttribute="bottom" constant="5" id="1JB-d1-zb9"/>
<constraint firstItem="oxX-IL-dG4" firstAttribute="top" secondItem="T1Q-RS-8o6" secondAttribute="bottom" constant="4" id="2DB-H2-E2v"/>
<constraint firstAttribute="bottom" secondItem="jta-3V-4wL" secondAttribute="bottom" id="3rt-Ig-1rG"/>
@ -103,18 +101,19 @@
<constraint firstAttribute="trailing" secondItem="Q6g-b0-3sZ" secondAttribute="trailing" id="Mf1-H6-oH4"/>
<constraint firstItem="Jkz-Zp-aaG" firstAttribute="centerX" secondItem="oxX-IL-dG4" secondAttribute="centerX" id="OQy-tF-e3Z"/>
<constraint firstItem="jta-3V-4wL" firstAttribute="centerX" secondItem="eCk-zY-LXq" secondAttribute="centerX" id="R87-mq-SlO"/>
<constraint firstItem="5Yd-df-HbB" firstAttribute="bottom" secondItem="T1Q-RS-8o6" secondAttribute="bottom" constant="2" id="RQU-MS-Qfr"/>
<constraint firstItem="Jkz-Zp-aaG" firstAttribute="top" secondItem="X8H-1U-wc3" secondAttribute="bottom" id="XDO-yX-Zs5"/>
<constraint firstItem="X8H-1U-wc3" firstAttribute="leading" secondItem="eCk-zY-LXq" secondAttribute="leading" constant="7" id="XU5-Lv-9Xn"/>
<constraint firstItem="T1Q-RS-8o6" firstAttribute="top" secondItem="eCk-zY-LXq" secondAttribute="top" constant="10" id="cc7-bg-15Z"/>
<constraint firstItem="Jkz-Zp-aaG" firstAttribute="leading" secondItem="eCk-zY-LXq" secondAttribute="leading" constant="7" id="fPh-Lb-Bv9"/>
<constraint firstItem="xws-BR-H47" firstAttribute="centerY" secondItem="T1Q-RS-8o6" secondAttribute="centerY" id="faX-hg-WfP"/>
<constraint firstItem="5Yd-df-HbB" firstAttribute="top" secondItem="eCk-zY-LXq" secondAttribute="top" constant="55" id="h4R-2d-Xxn"/>
<constraint firstAttribute="trailing" secondItem="oxX-IL-dG4" secondAttribute="trailing" constant="4" id="hDl-X9-M4n"/>
<constraint firstItem="T1Q-RS-8o6" firstAttribute="centerX" secondItem="eCk-zY-LXq" secondAttribute="centerX" id="hmB-fl-oN2"/>
<constraint firstItem="Q6g-b0-3sZ" firstAttribute="top" secondItem="eCk-zY-LXq" secondAttribute="top" constant="5" id="jST-Ic-lsn"/>
<constraint firstAttribute="trailing" secondItem="X8H-1U-wc3" secondAttribute="trailing" constant="7" id="o5i-7H-n0G"/>
<constraint firstAttribute="trailing" secondItem="Jkz-Zp-aaG" secondAttribute="trailing" constant="7" id="uQe-FG-3lb"/>
<constraint firstItem="X8H-1U-wc3" firstAttribute="top" secondItem="oxX-IL-dG4" secondAttribute="top" id="uTm-3W-QoM"/>
<constraint firstItem="5Yd-df-HbB" firstAttribute="trailing" secondItem="T1Q-RS-8o6" secondAttribute="trailing" constant="2" id="wqP-uJ-EaY"/>
</constraints>
<connections>
<outlet property="directRoomBorderView" destination="xws-BR-H47" id="34A-hu-DXq"/>
@ -131,6 +130,6 @@
</collectionViewCell>
</objects>
<resources>
<image name="e2e_verified" width="10" height="12"/>
<image name="encryption_normal" width="16" height="16"/>
</resources>
</document>

View file

@ -43,16 +43,16 @@ final class KeyBackupRecoverCoordinator: KeyBackupRecoverCoordinatorType {
// MARK: - Public
func start() {
let rootCoordinator: Coordinator & Presentable
// Check if a passphrase has been set for given backup
if let megolmBackupAuthData = MXMegolmBackupAuthData(fromJSON: self.keyBackupVersion.authData), megolmBackupAuthData.privateKeySalt != nil {
rootCoordinator = self.createRecoverFromPassphraseCoordinator()
// Check if we have the private key locally
if self.session.crypto.backup.hasPrivateKeyInCryptoStore {
rootCoordinator = self.createRecoverFromPrivateKeyCoordinator()
} else {
rootCoordinator = self.createRecoverFromRecoveryKeyCoordinator()
rootCoordinator = self.createRecoverWithUserInteractionCoordinator()
}
rootCoordinator.start()
self.add(childCoordinator: rootCoordinator)
@ -66,6 +66,24 @@ final class KeyBackupRecoverCoordinator: KeyBackupRecoverCoordinatorType {
// MARK: - Private
private func createRecoverWithUserInteractionCoordinator() -> Coordinator & Presentable {
let coordinator: Coordinator & Presentable
// Check if a passphrase has been set for given backup
if let megolmBackupAuthData = MXMegolmBackupAuthData(fromJSON: self.keyBackupVersion.authData), megolmBackupAuthData.privateKeySalt != nil {
coordinator = self.createRecoverFromPassphraseCoordinator()
} else {
coordinator = self.createRecoverFromRecoveryKeyCoordinator()
}
return coordinator
}
private func createRecoverFromPrivateKeyCoordinator() -> KeyBackupRecoverFromPrivateKeyCoordinator {
let coordinator = KeyBackupRecoverFromPrivateKeyCoordinator(keyBackup: self.session.crypto.backup, keyBackupVersion: self.keyBackupVersion)
coordinator.delegate = self
return coordinator
}
private func createRecoverFromPassphraseCoordinator() -> KeyBackupRecoverFromPassphraseCoordinator {
let coordinator = KeyBackupRecoverFromPassphraseCoordinator(keyBackup: self.session.crypto.backup, keyBackupVersion: self.keyBackupVersion)
coordinator.delegate = self
@ -95,6 +113,33 @@ final class KeyBackupRecoverCoordinator: KeyBackupRecoverCoordinatorType {
keyBackupRecoverSuccessViewController.delegate = self
self.navigationRouter.push(keyBackupRecoverSuccessViewController, animated: true, popCompletion: nil)
}
private func showRecoverFallback() {
let coordinator = self.createRecoverWithUserInteractionCoordinator()
self.add(childCoordinator: coordinator)
// Skip the previously displayed KeyBackupRecoverFromPrivateKeyCoordinator in the navigation stack
self.navigationRouter.setRootModule(coordinator)
coordinator.start()
}
}
// MARK: - KeyBackupRecoverFromPassphraseCoordinatorDelegate
extension KeyBackupRecoverCoordinator: KeyBackupRecoverFromPrivateKeyCoordinatorDelegate {
func keyBackupRecoverFromPrivateKeyCoordinatorDidRecover(_ coordinator: KeyBackupRecoverFromPrivateKeyCoordinatorType) {
self.showRecoverSuccess()
}
func keyBackupRecoverFromPrivateKeyCoordinatorDidPrivateKeyFail(_ coordinator: KeyBackupRecoverFromPrivateKeyCoordinatorType) {
// The private key did not work. Ask the user to enter their passphrase or recovery key
self.showRecoverFallback()
}
func keyBackupRecoverFromPrivateKeyCoordinatorDidCancel(_ coordinator: KeyBackupRecoverFromPrivateKeyCoordinatorType) {
self.delegate?.keyBackupRecoverCoordinatorDidCancel(self)
}
}
// MARK: - KeyBackupRecoverFromPassphraseCoordinatorDelegate
@ -125,7 +170,7 @@ extension KeyBackupRecoverCoordinator: KeyBackupRecoverFromRecoveryKeyCoordinato
// MARK: - KeyBackupRecoverSuccessViewControllerDelegate
extension KeyBackupRecoverCoordinator: KeyBackupRecoverSuccessViewControllerDelegate {
func KeyBackupRecoverSuccessViewControllerDidTapDone(_ keyBackupRecoverSuccessViewController: KeyBackupRecoverSuccessViewController) {
func keyBackupRecoverSuccessViewControllerDidTapDone(_ keyBackupRecoverSuccessViewController: KeyBackupRecoverSuccessViewController) {
self.delegate?.keyBackupRecoverCoordinatorDidRecover(self)
}
}

View file

@ -0,0 +1,37 @@
// File created from ScreenTemplate
// $ createScreen.sh KeyBackup/Recover/Loading KeyBackupRecoverDataLoading
/*
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 KeyBackupRecoverDataLoadingViewModelViewDelegate: class {
func keyBackupRecoverDataLoadingViewModel(_ viewModel: KeyBackupRecoverDataLoadingViewModelType, didUpdateViewState viewSate: KeyBackupRecoverDataLoadingViewState)
}
protocol KeyBackupRecoverDataLoadingViewModelCoordinatorDelegate: class {
func keyBackupRecoverDataLoadingViewModelDidRecover(_ viewModel: KeyBackupRecoverDataLoadingViewModelType)
func keyBackupRecoverDataLoadingViewModelDidCancel(_ viewModel: KeyBackupRecoverDataLoadingViewModelType)
}
/// Protocol describing the view model used by `KeyBackupRecoverDataLoadingViewController`
protocol KeyBackupRecoverDataLoadingViewModelType {
var viewDelegate: KeyBackupRecoverDataLoadingViewModelViewDelegate? { get set }
var coordinatorDelegate: KeyBackupRecoverDataLoadingViewModelCoordinatorDelegate? { get set }
func process(viewAction: KeyBackupRecoverDataLoadingViewAction)
}

View file

@ -0,0 +1,72 @@
// File created from ScreenTemplate
// $ createScreen.sh .KeyBackup/Recover/PrivateKey KeyBackupRecoverFromPrivateKey
/*
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 KeyBackupRecoverFromPrivateKeyCoordinator: KeyBackupRecoverFromPrivateKeyCoordinatorType {
// MARK: - Properties
// MARK: Private
private var keyBackupRecoverFromPrivateKeyViewModel: KeyBackupRecoverFromPrivateKeyViewModelType
private let keyBackupRecoverFromPrivateKeyViewController: KeyBackupRecoverFromPrivateKeyViewController
// MARK: Public
// Must be used only internally
var childCoordinators: [Coordinator] = []
weak var delegate: KeyBackupRecoverFromPrivateKeyCoordinatorDelegate?
// MARK: - Setup
init(keyBackup: MXKeyBackup, keyBackupVersion: MXKeyBackupVersion) {
let keyBackupRecoverFromPrivateKeyViewModel = KeyBackupRecoverFromPrivateKeyViewModel(keyBackup: keyBackup, keyBackupVersion: keyBackupVersion)
let keyBackupRecoverFromPrivateKeyViewController = KeyBackupRecoverFromPrivateKeyViewController.instantiate(with: keyBackupRecoverFromPrivateKeyViewModel)
self.keyBackupRecoverFromPrivateKeyViewModel = keyBackupRecoverFromPrivateKeyViewModel
self.keyBackupRecoverFromPrivateKeyViewController = keyBackupRecoverFromPrivateKeyViewController
}
// MARK: - Public methods
func start() {
self.keyBackupRecoverFromPrivateKeyViewModel.coordinatorDelegate = self
}
func toPresentable() -> UIViewController {
return self.keyBackupRecoverFromPrivateKeyViewController
}
}
// MARK: - KeyBackupRecoverFromPrivateKeyViewModelCoordinatorDelegate
extension KeyBackupRecoverFromPrivateKeyCoordinator: KeyBackupRecoverFromPrivateKeyViewModelCoordinatorDelegate {
func keyBackupRecoverFromPrivateKeyViewModelDidRecover(_ viewModel: KeyBackupRecoverFromPrivateKeyViewModelType) {
self.delegate?.keyBackupRecoverFromPrivateKeyCoordinatorDidRecover(self)
}
func keyBackupRecoverFromPrivateKeyViewModelDidPrivateKeyFail(_ viewModel: KeyBackupRecoverFromPrivateKeyViewModelType) {
self.delegate?.keyBackupRecoverFromPrivateKeyCoordinatorDidPrivateKeyFail(self)
}
func keyBackupRecoverFromPrivateKeyViewModelDidCancel(_ viewModel: KeyBackupRecoverFromPrivateKeyViewModelType) {
self.delegate?.keyBackupRecoverFromPrivateKeyCoordinatorDidCancel(self)
}
}

View file

@ -0,0 +1,30 @@
// File created from ScreenTemplate
// $ createScreen.sh .KeyBackup/Recover/PrivateKey KeyBackupRecoverFromPrivateKey
/*
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 KeyBackupRecoverFromPrivateKeyCoordinatorDelegate: class {
func keyBackupRecoverFromPrivateKeyCoordinatorDidRecover(_ coordinator: KeyBackupRecoverFromPrivateKeyCoordinatorType)
func keyBackupRecoverFromPrivateKeyCoordinatorDidPrivateKeyFail(_ coordinator: KeyBackupRecoverFromPrivateKeyCoordinatorType)
func keyBackupRecoverFromPrivateKeyCoordinatorDidCancel(_ coordinator: KeyBackupRecoverFromPrivateKeyCoordinatorType)
}
/// `KeyBackupRecoverFromPrivateKeyCoordinatorType` is a protocol describing a Coordinator that handle key backup setup passphrase navigation flow.
protocol KeyBackupRecoverFromPrivateKeyCoordinatorType: Coordinator, Presentable {
var delegate: KeyBackupRecoverFromPrivateKeyCoordinatorDelegate? { get }
}

View file

@ -0,0 +1,25 @@
// File created from ScreenTemplate
// $ createScreen.sh .KeyBackup/Recover/PrivateKey KeyBackupRecoverFromPrivateKey
/*
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
/// KeyBackupRecoverFromPrivateKeyViewController view actions exposed to view model
enum KeyBackupRecoverFromPrivateKeyViewAction {
case recover
case cancel
}

View file

@ -0,0 +1,97 @@
<?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="cb6-oF-e0m">
<device id="retina4_7" 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 Backup Recover Data Loading View Controller-->
<scene sceneID="JIv-4y-eqa">
<objects>
<viewController extendedLayoutIncludesOpaqueBars="YES" automaticallyAdjustsScrollViewInsets="NO" id="cb6-oF-e0m" customClass="KeyBackupRecoverFromPrivateKeyViewController" customModule="Riot" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="JOd-8G-rga">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="cUL-rS-rfi">
<rect key="frame" x="0.0" y="20" width="375" height="647"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="a4s-VR-9rG">
<rect key="frame" x="0.0" y="0.0" width="375" height="239"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="AA6-5y-aKB">
<rect key="frame" x="0.0" y="0.0" width="375" height="239"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="key_backup_logo" translatesAutoresizingMaskIntoConstraints="NO" id="c3s-XT-wGy">
<rect key="frame" x="163.5" y="35" width="48" height="46"/>
<constraints>
<constraint firstAttribute="height" constant="46" id="G7f-5x-wqu"/>
<constraint firstAttribute="width" constant="48" id="raJ-A8-OeL"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Restoring backup…" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1dN-Ld-mvf">
<rect key="frame" x="20" y="111" width="335" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="c3s-XT-wGy" firstAttribute="top" secondItem="AA6-5y-aKB" secondAttribute="top" constant="35" id="2hk-29-LeR"/>
<constraint firstItem="1dN-Ld-mvf" firstAttribute="top" secondItem="c3s-XT-wGy" secondAttribute="bottom" constant="30" id="7oJ-n1-Vec"/>
<constraint firstAttribute="trailing" secondItem="1dN-Ld-mvf" secondAttribute="trailing" constant="20" id="RRJ-XS-DKi"/>
<constraint firstItem="1dN-Ld-mvf" firstAttribute="leading" secondItem="AA6-5y-aKB" secondAttribute="leading" constant="20" id="bgC-6o-Qd3"/>
<constraint firstItem="c3s-XT-wGy" firstAttribute="centerX" secondItem="AA6-5y-aKB" secondAttribute="centerX" id="hhx-MR-Ssb"/>
<constraint firstAttribute="width" priority="750" constant="500" id="qn9-3x-Vus"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="AA6-5y-aKB" secondAttribute="trailing" id="9zl-EA-onb"/>
<constraint firstAttribute="bottom" secondItem="AA6-5y-aKB" secondAttribute="bottom" id="QEe-pI-nde"/>
<constraint firstItem="AA6-5y-aKB" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="a4s-VR-9rG" secondAttribute="leading" id="dUg-r0-GLK"/>
<constraint firstAttribute="height" constant="239" id="f7G-GL-m2p"/>
<constraint firstItem="AA6-5y-aKB" firstAttribute="centerX" secondItem="a4s-VR-9rG" secondAttribute="centerX" id="jfM-Ga-xmC"/>
<constraint firstItem="AA6-5y-aKB" firstAttribute="top" secondItem="a4s-VR-9rG" secondAttribute="top" id="sUF-Z1-GNm"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstAttribute="bottom" secondItem="a4s-VR-9rG" secondAttribute="bottom" id="1y5-kr-9rM"/>
<constraint firstItem="a4s-VR-9rG" firstAttribute="leading" secondItem="cUL-rS-rfi" secondAttribute="leading" id="C8p-p4-H7y"/>
<constraint firstItem="a4s-VR-9rG" firstAttribute="top" secondItem="cUL-rS-rfi" secondAttribute="top" id="Ex0-c1-ak8"/>
<constraint firstAttribute="trailing" secondItem="a4s-VR-9rG" secondAttribute="trailing" id="d6Y-su-yMj"/>
<constraint firstItem="a4s-VR-9rG" firstAttribute="width" secondItem="cUL-rS-rfi" secondAttribute="width" id="uTy-iK-Qq9"/>
</constraints>
</scrollView>
</subviews>
<color key="backgroundColor" red="0.94509803920000002" green="0.96078431369999995" blue="0.97254901959999995" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstItem="cUL-rS-rfi" firstAttribute="leading" secondItem="Y3k-2C-Pek" secondAttribute="leading" id="9ZI-Gm-3DT"/>
<constraint firstItem="Y3k-2C-Pek" firstAttribute="trailing" secondItem="cUL-rS-rfi" secondAttribute="trailing" id="QwC-RO-L6M"/>
<constraint firstItem="Y3k-2C-Pek" firstAttribute="top" secondItem="cUL-rS-rfi" secondAttribute="top" id="ffm-HV-RhA"/>
<constraint firstAttribute="bottom" secondItem="cUL-rS-rfi" secondAttribute="bottom" id="rib-a1-j68"/>
</constraints>
<viewLayoutGuide key="safeArea" id="Y3k-2C-Pek"/>
</view>
<connections>
<outlet property="informationLabel" destination="1dN-Ld-mvf" id="RAQ-9H-hXQ"/>
<outlet property="shieldImageView" destination="c3s-XT-wGy" id="jVg-AC-PGB"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dR3-YY-guh" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-3772" y="-774"/>
</scene>
</scenes>
<resources>
<image name="key_backup_logo" width="48" height="46"/>
</resources>
</document>

View file

@ -0,0 +1,158 @@
// File created from ScreenTemplate
// $ createScreen.sh .KeyBackup/Recover/PrivateKey KeyBackupRecoverFromPrivateKey
/*
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 KeyBackupRecoverFromPrivateKeyViewController: UIViewController {
// MARK: - Constants
// MARK: - Properties
// MARK: Outlets
@IBOutlet private weak var shieldImageView: UIImageView!
@IBOutlet private weak var informationLabel: UILabel!
// MARK: Private
private var viewModel: KeyBackupRecoverFromPrivateKeyViewModelType!
private var theme: Theme!
private var errorPresenter: MXKErrorPresentation!
private var activityPresenter: ActivityIndicatorPresenter!
// MARK: - Setup
class func instantiate(with viewModel: KeyBackupRecoverFromPrivateKeyViewModelType) -> KeyBackupRecoverFromPrivateKeyViewController {
let viewController = StoryboardScene.KeyBackupRecoverFromPrivateKeyViewController.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.title = VectorL10n.keyBackupRecoverTitle
self.setupViews()
self.activityPresenter = ActivityIndicatorPresenter()
self.errorPresenter = MXKErrorAlertPresentation()
self.registerThemeServiceDidChangeThemeNotification()
self.update(theme: self.theme)
self.viewModel.viewDelegate = self
self.viewModel.process(viewAction: .recover)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return self.theme.statusBarStyle
}
// MARK: - Private
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?.cancelButtonAction()
}
self.navigationItem.rightBarButtonItem = cancelBarButtonItem
let shieldImage = Asset.Images.keyBackupLogo.image.withRenderingMode(.alwaysTemplate)
self.shieldImageView.image = shieldImage
self.informationLabel.text = VectorL10n.keyBackupRecoverFromPrivateKeyInfo
}
private func update(theme: Theme) {
self.theme = theme
self.view.backgroundColor = theme.headerBackgroundColor
if let navigationBar = self.navigationController?.navigationBar {
theme.applyStyle(onNavigationBar: navigationBar)
}
self.shieldImageView.tintColor = theme.textPrimaryColor
self.informationLabel.textColor = theme.textPrimaryColor
}
private func render(viewState: KeyBackupRecoverFromPrivateKeyViewState) {
switch viewState {
case .loading:
self.renderLoading()
case .loaded:
self.renderLoaded()
case .error(let error):
self.render(error: error)
}
}
private func renderLoading() {
self.activityPresenter.presentActivityIndicator(on: self.view, animated: true)
}
private func renderLoaded() {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
}
private func render(error: Error) {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: nil)
}
// MARK: - Actions
private func cancelButtonAction() {
self.viewModel.process(viewAction: .cancel)
}
}
// MARK: - KeyBackupRecoverFromPrivateKeyViewModelViewDelegate
extension KeyBackupRecoverFromPrivateKeyViewController: KeyBackupRecoverFromPrivateKeyViewModelViewDelegate {
func keyBackupRecoverFromPrivateKeyViewModel(_ viewModel: KeyBackupRecoverFromPrivateKeyViewModelType, didUpdateViewState viewSate: KeyBackupRecoverFromPrivateKeyViewState) {
self.render(viewState: viewSate)
}
}

Some files were not shown because too many files have changed in this diff Show more