Merge branch 'release/1.0.13/master'

This commit is contained in:
manuroe 2020-09-30 19:01:07 +02:00
commit 402486ed1c
148 changed files with 5440 additions and 1197 deletions

View file

@ -1,38 +1,75 @@
Changes in 1.0.12 (2020-09-16)
Changes in 1.0.13 (2020-09-30)
=================================================
✨ Features
*
*
🙌 Improvements
*
* Room: Differentiate wordings for DMs.
* Room: New Room Settings screen.
* PIN code: Implement not allowed PINs feature. There is no restriction by default.
* PIN code: Do not show notification content and disable replies when protection set.
* PIN code: Log out user automatically after some wrong PINs/biometrics (#3623).
* Complete Security: Come back to the root screen if device verification is cancelled.
* Device verification: Add possibility to reset SSSS & Cross-Signing when recovery passphrase or key are lost.
* Architecture: Use coordinator pattern for legacy screen flows (#3597).
* Architecture: Create AppDelegate.handleAppState() as central point to handle application state.
🐛 Bugfix
*
* Timeline: Hide encrypted history (pre-invite) (#3660).
* PIN Code: Do not show verification dialog at the top of PIN code.
* Complete Security: Let the authentication flow display it if this flow is not complete yet.
* Device verification: Fix inactive cancel action issue in self verification flow.
* Fix floating action buttons' images.
* Various theme fixes.
⚠️ API Changes
*
*
🗣 Translations
*
*
🧱 Build
*
*
Others
*
*
Changes in 1.0.12 (2020-09-16)
✨ Features
*
🙌 Improvements
*
🐛 Bugfix
*
⚠️ API Changes
*
🗣 Translations
*
🧱 Build
*
Others
*
Improvements:
* Upgrade MatrixKit version ([v0.12.21](https://github.com/matrix-org/matrix-ios-kit/releases/tag/v0.12.21)).
* Upgrade MatrixKit version ([v0.12.20](https://github.com/matrix-org/matrix-ios-kit/releases/tag/v0.12.20)).
Changes in 1.0.11 (2020-09-15)
=================================================
✨ Features
*
*
🙌 Improvements
* Room: Collapse state messages on room creation (#3629).
* Room: Collapse state messages on room creation (#3629).
* AuthVC: Make force PIN working for registration as well.
* AppDelegate: Do not show incoming key verification requests while authenticating.
@ -41,13 +78,13 @@ Changes in 1.0.11 (2020-09-15)
* Loading animation: Fix the bug where, after authentication, the animation disappeared too early and made auth screen flashed.
⚠️ API Changes
*
*
🗣 Translations
*
*
🧱 Build
*
*
Others
* buildRelease.sh: Pass a `git_tag` parameter to fastlane because fastlane `git_branch` method can fail.
@ -59,28 +96,28 @@ Changes in 1.0.10 (2020-09-08)
=================================================
✨ Features
*
*
🙌 Improvements
* AppDelegate: Convert to Swift (#3594).
* Contextualize floating button actions per tab (#3627).
🐛 Bugfix
* Show pin code screen on every foreground (#3620).
* Show pin code screen on every foreground (#3620).
* Close keyboard on pin code screen (#3622).
* Fix content leakage on pin code protection (#3624).
⚠️ API Changes
*
*
🗣 Translations
*
*
🧱 Build
* buildRelease.sh: Make sure it works for both branches and tags
Others
*
*
Improvements:
* Upgrade MatrixKit version ([v0.12.18](https://github.com/matrix-org/matrix-ios-kit/releases/tag/v0.12.18)).

View file

@ -31,6 +31,9 @@ class AppConfiguration: CommonConfiguration {
// Enable CallKit for app
MXKAppSettings.standard()?.isCallKitEnabled = true
// Hide undecryptable messages that were sent while the user was not in the room
MXKAppSettings.standard()?.hidePreJoinedUndecryptableEvents = true
// Enable long press on event in bubble cells
MXKRoomBubbleTableViewCell.disableLongPressGesture(onEvent: false)

View file

@ -168,6 +168,22 @@ final class BuildSettings: NSObject {
static let allowLocalContactsAccess: Bool = true
// MARK: - Feature Specifics
/// Not allowed pin codes. User won't be able to select one of the pin in the list.
static let notAllowedPINs: [String] = []
/// Maximum number of allowed pin failures when unlocking, before force logging out the user. Defaults to `3`
static let maxAllowedNumberOfPinFailures: Int = 3
/// Maximum number of allowed biometrics failures when unlocking, before fallbacking the user to the pin if set or logging out the user. Defaults to `5`
static let maxAllowedNumberOfBiometricsFailures: Int = 5
/// Indicates should the app log out the user when number of PIN failures reaches `maxAllowedNumberOfPinFailures`. Defaults to `false`
static let logOutUserWhenPINFailuresExceeded: Bool = false
/// Indicates should the app log out the user when number of biometrics failures reaches `maxAllowedNumberOfBiometricsFailures`. Defaults to `false`
static let logOutUserWhenBiometricsFailuresExceeded: Bool = false
// MARK: - General Settings Screen

View file

@ -11,7 +11,7 @@ use_frameworks!
# - `{ {kit spec hash} => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for each repo. Used by Fastfile during CI
#
# Warning: our internal tooling depends on the name of this variable name, so be sure not to change it
$matrixKitVersion = '= 0.12.20'
$matrixKitVersion = '= 0.12.21'
# $matrixKitVersion = :local
# $matrixKitVersion = {'develop' => 'develop'}

View file

@ -52,38 +52,38 @@ PODS:
- MatomoTracker (7.2.1):
- MatomoTracker/Core (= 7.2.1)
- MatomoTracker/Core (7.2.1)
- MatrixKit (0.12.20):
- MatrixKit (0.12.21):
- cmark (~> 0.24.1)
- DTCoreText (~> 1.6.23)
- HPGrowingTextView (~> 1.1)
- libPhoneNumber-iOS (~> 0.9.13)
- MatrixKit/Core (= 0.12.20)
- MatrixSDK (= 0.16.15)
- MatrixKit/AppExtension (0.12.20):
- MatrixKit/Core (= 0.12.21)
- MatrixSDK (= 0.16.16)
- MatrixKit/AppExtension (0.12.21):
- cmark (~> 0.24.1)
- DTCoreText (~> 1.6.23)
- DTCoreText/Extension
- HPGrowingTextView (~> 1.1)
- libPhoneNumber-iOS (~> 0.9.13)
- MatrixSDK (= 0.16.15)
- MatrixKit/Core (0.12.20):
- MatrixSDK (= 0.16.16)
- MatrixKit/Core (0.12.21):
- cmark (~> 0.24.1)
- DTCoreText (~> 1.6.23)
- HPGrowingTextView (~> 1.1)
- libPhoneNumber-iOS (~> 0.9.13)
- MatrixSDK (= 0.16.15)
- MatrixSDK (0.16.15):
- MatrixSDK/Core (= 0.16.15)
- MatrixSDK/Core (0.16.15):
- MatrixSDK (= 0.16.16)
- MatrixSDK (0.16.16):
- MatrixSDK/Core (= 0.16.16)
- MatrixSDK/Core (0.16.16):
- AFNetworking (~> 4.0.0)
- GZIP (~> 1.2.2)
- libbase58 (~> 0.1.4)
- OLMKit (~> 3.1.0)
- Realm (~> 4.4.0)
- MatrixSDK/JingleCallStack (0.16.15):
- MatrixSDK/JingleCallStack (0.16.16):
- JitsiMeetSDK (~> 2.8.1)
- MatrixSDK/Core
- MatrixSDK/SwiftSupport (0.16.15):
- MatrixSDK/SwiftSupport (0.16.16):
- MatrixSDK/Core
- OLMKit (3.1.0):
- OLMKit/olmc (= 3.1.0)
@ -114,8 +114,8 @@ DEPENDENCIES:
- KeychainAccess (~> 4.2)
- KTCenterFlowLayout (~> 1.3.1)
- MatomoTracker (~> 7.2.0)
- MatrixKit (= 0.12.20)
- MatrixKit/AppExtension (= 0.12.20)
- MatrixKit (= 0.12.21)
- MatrixKit/AppExtension (= 0.12.21)
- MatrixSDK
- MatrixSDK/JingleCallStack
- MatrixSDK/SwiftSupport
@ -169,8 +169,8 @@ SPEC CHECKSUMS:
libbase58: 7c040313537b8c44b6e2d15586af8e21f7354efd
libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75
MatomoTracker: 246b6b0693cf39b356134dec7561f719d3538b96
MatrixKit: d7a0a05d6c880c493c3823f4bc203b1550994b33
MatrixSDK: 23ad718d0ca1175c8af12a8ad58f1e08d8aed46d
MatrixKit: 54e5497d25ac2a4b6b27094076f7188573677eb3
MatrixSDK: 12259762d604dd351313e4d9e65cc48e16377247
OLMKit: 4ee0159d63feeb86d836fdcfefe418e163511639
Realm: 4eb04d7487bd43c0581256f40b424eafb711deff
Reusable: 53a9acf5c536f229b31b5865782414b508252ddb
@ -179,6 +179,6 @@ SPEC CHECKSUMS:
zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
PODFILE CHECKSUM: 42729c01dc00e56b55fe47af73f2a3a13fa43fb4
PODFILE CHECKSUM: 9feca03c32e418290c0cf511efe1437e956654df
COCOAPODS: 1.9.3

View file

@ -186,6 +186,13 @@
B10A3E8E24FE4368007C380F /* ElementView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A3E8B24FE4367007C380F /* ElementView.swift */; };
B10A3E8F24FE4368007C380F /* Timeline_1.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A3E8C24FE4367007C380F /* Timeline_1.swift */; };
B10A3E9024FE4368007C380F /* ElementViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A3E8D24FE4367007C380F /* ElementViewController.swift */; };
B10A3E9324FE8254007C380F /* AppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A3E9124FE8254007C380F /* AppCoordinator.swift */; };
B10A3E9424FE8254007C380F /* AppCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A3E9224FE8254007C380F /* AppCoordinatorType.swift */; };
B10A3E9824FE86AF007C380F /* SplitViewCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A3E9624FE86AE007C380F /* SplitViewCoordinatorType.swift */; };
B10A3E9924FE86AF007C380F /* SplitViewCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A3E9724FE86AF007C380F /* SplitViewCoordinator.swift */; };
B10A3E9C24FE88CB007C380F /* RootRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A3E9A24FE88CA007C380F /* RootRouter.swift */; };
B10A3E9D24FE88CB007C380F /* RootRouterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A3E9B24FE88CB007C380F /* RootRouterType.swift */; };
B10A3E9F24FFC3E6007C380F /* PlaceholderDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A3E9E24FFC3E5007C380F /* PlaceholderDetailViewController.swift */; };
B10CFBC32268D99D00A5842E /* JitsiService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10CFBC22268D99D00A5842E /* JitsiService.swift */; };
B1107EC82200B0720038014B /* KeyBackupRecoverSuccessViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1107EC72200B0720038014B /* KeyBackupRecoverSuccessViewController.swift */; };
B1107ECA2200B09F0038014B /* KeyBackupRecoverSuccessViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B1107EC92200B09F0038014B /* KeyBackupRecoverSuccessViewController.storyboard */; };
@ -202,6 +209,14 @@
B125FE1F231D5DF700B72806 /* SettingsDiscoveryViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B125FE1E231D5DF700B72806 /* SettingsDiscoveryViewModelType.swift */; };
B125FE21231D5E1D00B72806 /* SettingsDiscoveryViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B125FE20231D5E1D00B72806 /* SettingsDiscoveryViewAction.swift */; };
B125FE23231D5E4300B72806 /* SettingsDiscoveryViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B125FE22231D5E4300B72806 /* SettingsDiscoveryViewState.swift */; };
B12676832523E4D100BE6B98 /* SecretsResetCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B126767B2523E4D100BE6B98 /* SecretsResetCoordinator.swift */; };
B12676842523E4D100BE6B98 /* SecretsResetViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B126767C2523E4D100BE6B98 /* SecretsResetViewModelType.swift */; };
B12676852523E4D100BE6B98 /* SecretsResetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B126767D2523E4D100BE6B98 /* SecretsResetViewController.swift */; };
B12676862523E4D100BE6B98 /* SecretsResetCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B126767E2523E4D100BE6B98 /* SecretsResetCoordinatorType.swift */; };
B12676872523E4D100BE6B98 /* SecretsResetViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B126767F2523E4D100BE6B98 /* SecretsResetViewController.storyboard */; };
B12676882523E4D100BE6B98 /* SecretsResetViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B12676802523E4D100BE6B98 /* SecretsResetViewState.swift */; };
B12676892523E4D100BE6B98 /* SecretsResetViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B12676812523E4D100BE6B98 /* SecretsResetViewAction.swift */; };
B126768A2523E4D100BE6B98 /* SecretsResetViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B12676822523E4D100BE6B98 /* SecretsResetViewModel.swift */; };
B12C56EF2396CB5E00FAC6DE /* RoomMessageURLParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = B12C56EE2396CB5E00FAC6DE /* RoomMessageURLParser.swift */; };
B12D79FB23E2462200FACEDC /* UserVerificationStartCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B12D79F323E2462000FACEDC /* UserVerificationStartCoordinator.swift */; };
B12D79FC23E2462200FACEDC /* UserVerificationStartViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B12D79F423E2462100FACEDC /* UserVerificationStartViewController.storyboard */; };
@ -653,6 +668,9 @@
B1C562E5228C7C8D0037F12A /* RoomContextualMenuViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B1C562E0228C7C8C0037F12A /* RoomContextualMenuViewController.storyboard */; };
B1C562E8228C7CF20037F12A /* ContextualMenuItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C562E6228C7CF10037F12A /* ContextualMenuItemView.swift */; };
B1C562E9228C7CF20037F12A /* ContextualMenuItemView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B1C562E7228C7CF20037F12A /* ContextualMenuItemView.xib */; };
B1C7822F2500EAF500337EB9 /* TabBarCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C7822D2500EAF400337EB9 /* TabBarCoordinator.swift */; };
B1C782302500EAF500337EB9 /* TabBarCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C7822E2500EAF500337EB9 /* TabBarCoordinatorType.swift */; };
B1C782322500F96700337EB9 /* SplitViewPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C782312500F96600337EB9 /* SplitViewPresentable.swift */; };
B1CA3A2721EF6914000D1D89 /* UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1CA3A2621EF6913000D1D89 /* UIViewController.swift */; };
B1CA3A2921EF692B000D1D89 /* UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1CA3A2821EF692B000D1D89 /* UIView.swift */; };
B1CE83B62422812100D07506 /* KeyVerificationCoordinatorBridgePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1CE83B52422812000D07506 /* KeyVerificationCoordinatorBridgePresenter.swift */; };
@ -756,14 +774,35 @@
EC1CA8DA24D811B400DE9EBF /* NSE-Common.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = EC1CA8D924D811B400DE9EBF /* NSE-Common.xcconfig */; };
EC2B4EF124A1EEBD005EB739 /* DataProtectionHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC2B4EF024A1EEBD005EB739 /* DataProtectionHelper.swift */; };
EC2B4EF224A1EF34005EB739 /* DataProtectionHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC2B4EF024A1EEBD005EB739 /* DataProtectionHelper.swift */; };
EC31F012251B4DBD00D407DA /* RoomInfoListViewData.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC31F011251B4DBD00D407DA /* RoomInfoListViewData.swift */; };
EC31F014251B53AD00D407DA /* RoomInfoBasicView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC31F013251B53AD00D407DA /* RoomInfoBasicView.swift */; };
EC31F016251B53BC00D407DA /* RoomInfoBasicView.xib in Resources */ = {isa = PBXBuildFile; fileRef = EC31F015251B53BC00D407DA /* RoomInfoBasicView.xib */; };
EC31F0942521FC3700D407DA /* LocalAuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC1CA87924C8841C00DE9EBF /* LocalAuthenticationService.swift */; };
EC31F0952521FC4600D407DA /* PinCodePreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC1CA86D24C5BA4500DE9EBF /* PinCodePreferences.swift */; };
EC31F0962521FC5300D407DA /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1098BDA21ECE09E000DDA48 /* Strings.swift */; };
EC31F0972521FC6300D407DA /* Images.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1098BDC21ECE09E000DDA48 /* Images.swift */; };
EC31F09A2524A60E00D407DA /* BiometricsAuthenticationPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC31F0992524A60E00D407DA /* BiometricsAuthenticationPresenter.swift */; };
EC31F09C2524AE1400D407DA /* BiometricsAuthenticationPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC31F0992524A60E00D407DA /* BiometricsAuthenticationPresenter.swift */; };
EC3B066924AC6ADE000DF9BF /* CrossSigningService.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC3B066424AC6ADD000DF9BF /* CrossSigningService.swift */; };
EC3B066A24AC6ADE000DF9BF /* CrossSigningSetupBannerCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = EC3B066624AC6ADD000DF9BF /* CrossSigningSetupBannerCell.xib */; };
EC3B066B24AC6ADE000DF9BF /* CrossSigningBannerPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC3B066724AC6ADD000DF9BF /* CrossSigningBannerPreferences.swift */; };
EC3B066C24AC6ADE000DF9BF /* CrossSigningSetupBannerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC3B066824AC6ADD000DF9BF /* CrossSigningSetupBannerCell.swift */; };
EC49F5F92515016F003894A6 /* RoomInfoBasicViewData.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC49F5F82515016F003894A6 /* RoomInfoBasicViewData.swift */; };
EC51E78D250FC15000AAE7DB /* RoomCreationEventRowViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E78C250FC15000AAE7DB /* RoomCreationEventRowViewModel.swift */; };
EC51E7902510B7C700AAE7DB /* AutosizedTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E78F2510B7C700AAE7DB /* AutosizedTableView.swift */; };
EC51E7922510C0A500AAE7DB /* SpanningSlidingModalContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E7912510C0A500AAE7DB /* SpanningSlidingModalContainerView.swift */; };
EC51E7942510C0D000AAE7DB /* SpanningSlidingModalContainerView.xib in Resources */ = {isa = PBXBuildFile; fileRef = EC51E7932510C0D000AAE7DB /* SpanningSlidingModalContainerView.xib */; };
EC51E7A62514D2E100AAE7DB /* RoomInfoCoordinatorBridgePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E79A2514D2E000AAE7DB /* RoomInfoCoordinatorBridgePresenter.swift */; };
EC51E7A72514D2E100AAE7DB /* RoomInfoCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E79B2514D2E000AAE7DB /* RoomInfoCoordinator.swift */; };
EC51E7A82514D2E100AAE7DB /* RoomInfoListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E79D2514D2E100AAE7DB /* RoomInfoListViewController.swift */; };
EC51E7A92514D2E100AAE7DB /* RoomInfoListViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E79E2514D2E100AAE7DB /* RoomInfoListViewModelType.swift */; };
EC51E7AA2514D2E100AAE7DB /* RoomInfoListViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EC51E79F2514D2E100AAE7DB /* RoomInfoListViewController.storyboard */; };
EC51E7AB2514D2E100AAE7DB /* RoomInfoListViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E7A02514D2E100AAE7DB /* RoomInfoListViewState.swift */; };
EC51E7AC2514D2E100AAE7DB /* RoomInfoListCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E7A12514D2E100AAE7DB /* RoomInfoListCoordinatorType.swift */; };
EC51E7AD2514D2E100AAE7DB /* RoomInfoListCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E7A22514D2E100AAE7DB /* RoomInfoListCoordinator.swift */; };
EC51E7AE2514D2E100AAE7DB /* RoomInfoListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E7A32514D2E100AAE7DB /* RoomInfoListViewModel.swift */; };
EC51E7AF2514D2E100AAE7DB /* RoomInfoListViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E7A42514D2E100AAE7DB /* RoomInfoListViewAction.swift */; };
EC51E7B02514D2E100AAE7DB /* RoomInfoCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E7A52514D2E100AAE7DB /* RoomInfoCoordinatorType.swift */; };
EC619C1924DAD96000663A80 /* UIScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC619C1824DAD96000663A80 /* UIScrollView.swift */; };
EC711B4624A63B13008F830C /* MXRecoveryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC711B4524A63B13008F830C /* MXRecoveryService.swift */; };
EC711B7424A63B37008F830C /* SecretsSetupRecoveryKeyViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC711B4A24A63B36008F830C /* SecretsSetupRecoveryKeyViewModelType.swift */; };
@ -896,7 +935,7 @@
ECFBD5D7250A7AAF00DD5F5A /* RoomsDirectoryCoordinatorBridgePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECFBD5C7250A7AAF00DD5F5A /* RoomsDirectoryCoordinatorBridgePresenter.swift */; };
ECFBD5D8250A7AAF00DD5F5A /* RoomsDirectoryCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECFBD5C8250A7AAF00DD5F5A /* RoomsDirectoryCoordinatorType.swift */; };
ECFBD5DA250A7ABD00DD5F5A /* MXThirdPartyProtocolInstance.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECFBD5D9250A7ABD00DD5F5A /* MXThirdPartyProtocolInstance.swift */; };
ECFBD5DC250A82B200DD5F5A /* TableViewHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECFBD5DB250A82B200DD5F5A /* TableViewHeaderFooterView.swift */; };
ECFBD5DC250A82B200DD5F5A /* TextViewTableViewHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECFBD5DB250A82B200DD5F5A /* TextViewTableViewHeaderFooterView.swift */; };
ECFBD5E0250B684E00DD5F5A /* ChooseAvatarTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECFBD5DE250B684E00DD5F5A /* ChooseAvatarTableViewCell.swift */; };
ECFBD5E1250B684E00DD5F5A /* ChooseAvatarTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = ECFBD5DF250B684E00DD5F5A /* ChooseAvatarTableViewCell.xib */; };
ECFBD5E3250B6CAB00DD5F5A /* ChooseAvatarTableViewCellVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECFBD5E2250B6CAB00DD5F5A /* ChooseAvatarTableViewCellVM.swift */; };
@ -1173,6 +1212,13 @@
B10A3E8B24FE4367007C380F /* ElementView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ElementView.swift; sourceTree = "<group>"; };
B10A3E8C24FE4367007C380F /* Timeline_1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Timeline_1.swift; sourceTree = "<group>"; };
B10A3E8D24FE4367007C380F /* ElementViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ElementViewController.swift; sourceTree = "<group>"; };
B10A3E9124FE8254007C380F /* AppCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppCoordinator.swift; sourceTree = "<group>"; };
B10A3E9224FE8254007C380F /* AppCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppCoordinatorType.swift; sourceTree = "<group>"; };
B10A3E9624FE86AE007C380F /* SplitViewCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SplitViewCoordinatorType.swift; sourceTree = "<group>"; };
B10A3E9724FE86AF007C380F /* SplitViewCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SplitViewCoordinator.swift; sourceTree = "<group>"; };
B10A3E9A24FE88CA007C380F /* RootRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootRouter.swift; sourceTree = "<group>"; };
B10A3E9B24FE88CB007C380F /* RootRouterType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootRouterType.swift; sourceTree = "<group>"; };
B10A3E9E24FFC3E5007C380F /* PlaceholderDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaceholderDetailViewController.swift; sourceTree = "<group>"; };
B10CFBC22268D99D00A5842E /* JitsiService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JitsiService.swift; sourceTree = "<group>"; };
B1107EC72200B0720038014B /* KeyBackupRecoverSuccessViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyBackupRecoverSuccessViewController.swift; sourceTree = "<group>"; };
B1107EC92200B09F0038014B /* KeyBackupRecoverSuccessViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = KeyBackupRecoverSuccessViewController.storyboard; sourceTree = "<group>"; };
@ -1189,6 +1235,14 @@
B125FE1E231D5DF700B72806 /* SettingsDiscoveryViewModelType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsDiscoveryViewModelType.swift; sourceTree = "<group>"; };
B125FE20231D5E1D00B72806 /* SettingsDiscoveryViewAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsDiscoveryViewAction.swift; sourceTree = "<group>"; };
B125FE22231D5E4300B72806 /* SettingsDiscoveryViewState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsDiscoveryViewState.swift; sourceTree = "<group>"; };
B126767B2523E4D100BE6B98 /* SecretsResetCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsResetCoordinator.swift; sourceTree = "<group>"; };
B126767C2523E4D100BE6B98 /* SecretsResetViewModelType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsResetViewModelType.swift; sourceTree = "<group>"; };
B126767D2523E4D100BE6B98 /* SecretsResetViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsResetViewController.swift; sourceTree = "<group>"; };
B126767E2523E4D100BE6B98 /* SecretsResetCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsResetCoordinatorType.swift; sourceTree = "<group>"; };
B126767F2523E4D100BE6B98 /* SecretsResetViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = SecretsResetViewController.storyboard; sourceTree = "<group>"; };
B12676802523E4D100BE6B98 /* SecretsResetViewState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsResetViewState.swift; sourceTree = "<group>"; };
B12676812523E4D100BE6B98 /* SecretsResetViewAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsResetViewAction.swift; sourceTree = "<group>"; };
B12676822523E4D100BE6B98 /* SecretsResetViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsResetViewModel.swift; sourceTree = "<group>"; };
B12C56EE2396CB5E00FAC6DE /* RoomMessageURLParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMessageURLParser.swift; sourceTree = "<group>"; };
B12D79F323E2462000FACEDC /* UserVerificationStartCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserVerificationStartCoordinator.swift; sourceTree = "<group>"; };
B12D79F423E2462100FACEDC /* UserVerificationStartViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = UserVerificationStartViewController.storyboard; sourceTree = "<group>"; };
@ -1832,6 +1886,9 @@
B1C6FFE723954CE70055347B /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/InfoPlist.strings; sourceTree = "<group>"; };
B1C6FFE823954D3B0055347B /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
B1C6FFE923954D4B0055347B /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Vector.strings; sourceTree = "<group>"; };
B1C7822D2500EAF400337EB9 /* TabBarCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabBarCoordinator.swift; sourceTree = "<group>"; };
B1C7822E2500EAF500337EB9 /* TabBarCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabBarCoordinatorType.swift; sourceTree = "<group>"; };
B1C782312500F96600337EB9 /* SplitViewPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplitViewPresentable.swift; sourceTree = "<group>"; };
B1CA3A2621EF6913000D1D89 /* UIViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewController.swift; sourceTree = "<group>"; };
B1CA3A2821EF692B000D1D89 /* UIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIView.swift; sourceTree = "<group>"; };
B1CE83B52422812000D07506 /* KeyVerificationCoordinatorBridgePresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyVerificationCoordinatorBridgePresenter.swift; sourceTree = "<group>"; };
@ -1943,14 +2000,30 @@
EC1CA8D724D8118400DE9EBF /* SiriIntents-Common.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "SiriIntents-Common.xcconfig"; sourceTree = "<group>"; };
EC1CA8D924D811B400DE9EBF /* NSE-Common.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "NSE-Common.xcconfig"; sourceTree = "<group>"; };
EC2B4EF024A1EEBD005EB739 /* DataProtectionHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataProtectionHelper.swift; sourceTree = "<group>"; };
EC31F011251B4DBD00D407DA /* RoomInfoListViewData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomInfoListViewData.swift; sourceTree = "<group>"; };
EC31F013251B53AD00D407DA /* RoomInfoBasicView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomInfoBasicView.swift; sourceTree = "<group>"; };
EC31F015251B53BC00D407DA /* RoomInfoBasicView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RoomInfoBasicView.xib; sourceTree = "<group>"; };
EC31F0992524A60E00D407DA /* BiometricsAuthenticationPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BiometricsAuthenticationPresenter.swift; sourceTree = "<group>"; };
EC3B066424AC6ADD000DF9BF /* CrossSigningService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CrossSigningService.swift; sourceTree = "<group>"; };
EC3B066624AC6ADD000DF9BF /* CrossSigningSetupBannerCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CrossSigningSetupBannerCell.xib; sourceTree = "<group>"; };
EC3B066724AC6ADD000DF9BF /* CrossSigningBannerPreferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CrossSigningBannerPreferences.swift; sourceTree = "<group>"; };
EC3B066824AC6ADD000DF9BF /* CrossSigningSetupBannerCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CrossSigningSetupBannerCell.swift; sourceTree = "<group>"; };
EC49F5F82515016F003894A6 /* RoomInfoBasicViewData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomInfoBasicViewData.swift; sourceTree = "<group>"; };
EC51E78C250FC15000AAE7DB /* RoomCreationEventRowViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomCreationEventRowViewModel.swift; sourceTree = "<group>"; };
EC51E78F2510B7C700AAE7DB /* AutosizedTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutosizedTableView.swift; sourceTree = "<group>"; };
EC51E7912510C0A500AAE7DB /* SpanningSlidingModalContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpanningSlidingModalContainerView.swift; sourceTree = "<group>"; };
EC51E7932510C0D000AAE7DB /* SpanningSlidingModalContainerView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SpanningSlidingModalContainerView.xib; sourceTree = "<group>"; };
EC51E79A2514D2E000AAE7DB /* RoomInfoCoordinatorBridgePresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomInfoCoordinatorBridgePresenter.swift; sourceTree = "<group>"; };
EC51E79B2514D2E000AAE7DB /* RoomInfoCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomInfoCoordinator.swift; sourceTree = "<group>"; };
EC51E79D2514D2E100AAE7DB /* RoomInfoListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomInfoListViewController.swift; sourceTree = "<group>"; };
EC51E79E2514D2E100AAE7DB /* RoomInfoListViewModelType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomInfoListViewModelType.swift; sourceTree = "<group>"; };
EC51E79F2514D2E100AAE7DB /* RoomInfoListViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = RoomInfoListViewController.storyboard; sourceTree = "<group>"; };
EC51E7A02514D2E100AAE7DB /* RoomInfoListViewState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomInfoListViewState.swift; sourceTree = "<group>"; };
EC51E7A12514D2E100AAE7DB /* RoomInfoListCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomInfoListCoordinatorType.swift; sourceTree = "<group>"; };
EC51E7A22514D2E100AAE7DB /* RoomInfoListCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomInfoListCoordinator.swift; sourceTree = "<group>"; };
EC51E7A32514D2E100AAE7DB /* RoomInfoListViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomInfoListViewModel.swift; sourceTree = "<group>"; };
EC51E7A42514D2E100AAE7DB /* RoomInfoListViewAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomInfoListViewAction.swift; sourceTree = "<group>"; };
EC51E7A52514D2E100AAE7DB /* RoomInfoCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomInfoCoordinatorType.swift; sourceTree = "<group>"; };
EC619C1824DAD96000663A80 /* UIScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIScrollView.swift; sourceTree = "<group>"; };
EC711B4524A63B13008F830C /* MXRecoveryService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXRecoveryService.swift; sourceTree = "<group>"; };
EC711B4A24A63B36008F830C /* SecretsSetupRecoveryKeyViewModelType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsSetupRecoveryKeyViewModelType.swift; sourceTree = "<group>"; };
@ -2085,7 +2158,7 @@
ECFBD5C7250A7AAF00DD5F5A /* RoomsDirectoryCoordinatorBridgePresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomsDirectoryCoordinatorBridgePresenter.swift; sourceTree = "<group>"; };
ECFBD5C8250A7AAF00DD5F5A /* RoomsDirectoryCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomsDirectoryCoordinatorType.swift; sourceTree = "<group>"; };
ECFBD5D9250A7ABD00DD5F5A /* MXThirdPartyProtocolInstance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXThirdPartyProtocolInstance.swift; sourceTree = "<group>"; };
ECFBD5DB250A82B200DD5F5A /* TableViewHeaderFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewHeaderFooterView.swift; sourceTree = "<group>"; };
ECFBD5DB250A82B200DD5F5A /* TextViewTableViewHeaderFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewTableViewHeaderFooterView.swift; sourceTree = "<group>"; };
ECFBD5DE250B684E00DD5F5A /* ChooseAvatarTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChooseAvatarTableViewCell.swift; sourceTree = "<group>"; };
ECFBD5DF250B684E00DD5F5A /* ChooseAvatarTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ChooseAvatarTableViewCell.xib; sourceTree = "<group>"; };
ECFBD5E2250B6CAB00DD5F5A /* ChooseAvatarTableViewCellVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChooseAvatarTableViewCellVM.swift; sourceTree = "<group>"; };
@ -2660,6 +2733,8 @@
B1098C0B21ED07E4000DDA48 /* Presentable.swift */,
B1098C0C21ED07E4000DDA48 /* NavigationRouterType.swift */,
B1098C0821ED07E4000DDA48 /* NavigationRouter.swift */,
B10A3E9B24FE88CB007C380F /* RootRouterType.swift */,
B10A3E9A24FE88CA007C380F /* RootRouter.swift */,
);
path = Routers;
sourceTree = "<group>";
@ -2674,6 +2749,19 @@
path = LoadingAnimation;
sourceTree = "<group>";
};
B10A3E9524FE86AE007C380F /* SplitView */ = {
isa = PBXGroup;
children = (
B10A3E9624FE86AE007C380F /* SplitViewCoordinatorType.swift */,
B10A3E9724FE86AF007C380F /* SplitViewCoordinator.swift */,
B1B556EC20EE6C4C00210D55 /* RiotSplitViewController.h */,
B1B556EB20EE6C4C00210D55 /* RiotSplitViewController.m */,
B10A3E9E24FFC3E5007C380F /* PlaceholderDetailViewController.swift */,
B1C782312500F96600337EB9 /* SplitViewPresentable.swift */,
);
path = SplitView;
sourceTree = "<group>";
};
B1107EC62200B0190038014B /* Success */ = {
isa = PBXGroup;
children = (
@ -2717,6 +2805,21 @@
path = Discovery;
sourceTree = "<group>";
};
B126767A2523E4D100BE6B98 /* Reset */ = {
isa = PBXGroup;
children = (
B126767B2523E4D100BE6B98 /* SecretsResetCoordinator.swift */,
B126767C2523E4D100BE6B98 /* SecretsResetViewModelType.swift */,
B126767D2523E4D100BE6B98 /* SecretsResetViewController.swift */,
B126767E2523E4D100BE6B98 /* SecretsResetCoordinatorType.swift */,
B126767F2523E4D100BE6B98 /* SecretsResetViewController.storyboard */,
B12676802523E4D100BE6B98 /* SecretsResetViewState.swift */,
B12676812523E4D100BE6B98 /* SecretsResetViewAction.swift */,
B12676822523E4D100BE6B98 /* SecretsResetViewModel.swift */,
);
path = Reset;
sourceTree = "<group>";
};
B12C56ED2396CB0100FAC6DE /* RoomMessageLinkParser */ = {
isa = PBXGroup;
children = (
@ -3278,12 +3381,12 @@
children = (
ECF57A3725090C23004BBF9D /* CreateRoom */,
B1BB648724FD07B3008238AE /* Application */,
B10A3E9524FE86AE007C380F /* SplitView */,
EC1CA84F24C1DEC400DE9EBF /* SetPinCode */,
EC3B066324AC6ADD000DF9BF /* CrossSigning */,
EC711BB424A63C11008F830C /* AuthenticatedSession */,
EC711B9A24A63B58008F830C /* SecureBackup */,
EC711B4724A63B36008F830C /* Secrets */,
B1B556EA20EE6C4C00210D55 /* Main */,
B1560DA024B65A9500490F50 /* LaunchLoading */,
B1B556CA20EE6C4C00210D55 /* TabBar */,
B1B556F920EE6C4C00210D55 /* Authentication */,
@ -3392,6 +3495,7 @@
B1B5568E20EE6C4C00210D55 /* Room */ = {
isa = PBXGroup;
children = (
EC51E7B12514D34200AAE7DB /* RoomInfo */,
ECFBD605250FA98900DD5F5A /* CreationModal */,
32A6000C22C661100042C1D9 /* EditHistory */,
B1B5568F20EE6C4C00210D55 /* RoomViewController.h */,
@ -3583,6 +3687,8 @@
B1B556CA20EE6C4C00210D55 /* TabBar */ = {
isa = PBXGroup;
children = (
B1C7822E2500EAF500337EB9 /* TabBarCoordinatorType.swift */,
B1C7822D2500EAF400337EB9 /* TabBarCoordinator.swift */,
B1B556CB20EE6C4C00210D55 /* MasterTabBarController.h */,
B1B556CC20EE6C4C00210D55 /* MasterTabBarController.m */,
);
@ -3691,15 +3797,6 @@
path = People;
sourceTree = "<group>";
};
B1B556EA20EE6C4C00210D55 /* Main */ = {
isa = PBXGroup;
children = (
B1B556EC20EE6C4C00210D55 /* RiotSplitViewController.h */,
B1B556EB20EE6C4C00210D55 /* RiotSplitViewController.m */,
);
path = Main;
sourceTree = "<group>";
};
B1B556ED20EE6C4C00210D55 /* MediaPicker */ = {
isa = PBXGroup;
children = (
@ -4478,6 +4575,8 @@
B1BB649224FD428A008238AE /* AppDelegate.swift */,
F083BB0C1E7009EC00A9B29C /* LegacyAppDelegate.h */,
F083BB0D1E7009EC00A9B29C /* LegacyAppDelegate.m */,
B10A3E9224FE8254007C380F /* AppCoordinatorType.swift */,
B10A3E9124FE8254007C380F /* AppCoordinator.swift */,
);
path = Application;
sourceTree = "<group>";
@ -4753,6 +4852,7 @@
EC1CA88C24C9C9A200DE9EBF /* SetupBiometrics */ = {
isa = PBXGroup;
children = (
EC31F0992524A60E00D407DA /* BiometricsAuthenticationPresenter.swift */,
EC1CA88D24C9C9A200DE9EBF /* SetupBiometricsViewController.swift */,
EC1CA88E24C9C9A200DE9EBF /* SetupBiometricsCoordinator.swift */,
EC1CA88F24C9C9A200DE9EBF /* SetupBiometricsViewModelType.swift */,
@ -4784,6 +4884,16 @@
path = Banners;
sourceTree = "<group>";
};
EC49F5F32514FFCA003894A6 /* Views */ = {
isa = PBXGroup;
children = (
EC49F5F82515016F003894A6 /* RoomInfoBasicViewData.swift */,
EC31F013251B53AD00D407DA /* RoomInfoBasicView.swift */,
EC31F015251B53BC00D407DA /* RoomInfoBasicView.xib */,
);
path = Views;
sourceTree = "<group>";
};
EC51E78B250FC12A00AAE7DB /* Models */ = {
isa = PBXGroup;
children = (
@ -4800,11 +4910,40 @@
path = TableView;
sourceTree = "<group>";
};
EC51E79C2514D2E100AAE7DB /* RoomInfoList */ = {
isa = PBXGroup;
children = (
EC49F5F32514FFCA003894A6 /* Views */,
EC51E79D2514D2E100AAE7DB /* RoomInfoListViewController.swift */,
EC51E79E2514D2E100AAE7DB /* RoomInfoListViewModelType.swift */,
EC51E79F2514D2E100AAE7DB /* RoomInfoListViewController.storyboard */,
EC51E7A02514D2E100AAE7DB /* RoomInfoListViewState.swift */,
EC31F011251B4DBD00D407DA /* RoomInfoListViewData.swift */,
EC51E7A12514D2E100AAE7DB /* RoomInfoListCoordinatorType.swift */,
EC51E7A22514D2E100AAE7DB /* RoomInfoListCoordinator.swift */,
EC51E7A32514D2E100AAE7DB /* RoomInfoListViewModel.swift */,
EC51E7A42514D2E100AAE7DB /* RoomInfoListViewAction.swift */,
);
path = RoomInfoList;
sourceTree = "<group>";
};
EC51E7B12514D34200AAE7DB /* RoomInfo */ = {
isa = PBXGroup;
children = (
EC51E79B2514D2E000AAE7DB /* RoomInfoCoordinator.swift */,
EC51E79A2514D2E000AAE7DB /* RoomInfoCoordinatorBridgePresenter.swift */,
EC51E7A52514D2E100AAE7DB /* RoomInfoCoordinatorType.swift */,
EC51E79C2514D2E100AAE7DB /* RoomInfoList */,
);
path = RoomInfo;
sourceTree = "<group>";
};
EC711B4724A63B36008F830C /* Secrets */ = {
isa = PBXGroup;
children = (
EC711B4824A63B36008F830C /* Setup */,
EC711B5C24A63B36008F830C /* Recover */,
B126767A2523E4D100BE6B98 /* Reset */,
);
path = Secrets;
sourceTree = "<group>";
@ -5065,7 +5204,7 @@
children = (
ECF57A6025093B04004BBF9D /* SectionHeaderView.m */,
ECF57A6125093B04004BBF9D /* SectionHeaderView.h */,
ECFBD5DB250A82B200DD5F5A /* TableViewHeaderFooterView.swift */,
ECFBD5DB250A82B200DD5F5A /* TextViewTableViewHeaderFooterView.swift */,
);
path = SectionHeaders;
sourceTree = "<group>";
@ -5090,7 +5229,7 @@
isa = PBXGroup;
children = (
ECFBD5B9250A7AAF00DD5F5A /* Room */,
ECFBD5BD250A7AAF00DD5F5A /* Directory */,
ECFBD5BD250A7AAF00DD5F5A /* Network */,
);
path = Cells;
sourceTree = "<group>";
@ -5105,13 +5244,13 @@
path = Room;
sourceTree = "<group>";
};
ECFBD5BD250A7AAF00DD5F5A /* Directory */ = {
ECFBD5BD250A7AAF00DD5F5A /* Network */ = {
isa = PBXGroup;
children = (
ECFBD5BE250A7AAF00DD5F5A /* DirectoryNetworkTableHeaderFooterView.xib */,
ECFBD5BF250A7AAF00DD5F5A /* DirectoryNetworkTableHeaderFooterView.swift */,
);
path = Directory;
path = Network;
sourceTree = "<group>";
};
ECFBD5DD250B683300DD5F5A /* Cells */ = {
@ -5594,6 +5733,7 @@
B1CE83D32422817200D07506 /* KeyVerificationVerifiedViewController.storyboard in Resources */,
B1B5590020EF768F00210D55 /* RoomOutgoingTextMsgWithoutSenderNameBubbleCell.xib in Resources */,
B1B5597020EFA85D00210D55 /* EncryptionInfoView.xib in Resources */,
EC51E7AA2514D2E100AAE7DB /* RoomInfoListViewController.storyboard in Resources */,
B1B558BC20EF768F00210D55 /* RoomMembershipBubbleCell.xib in Resources */,
B1B5571F20EE6C4D00210D55 /* ContactDetailsViewController.xib in Resources */,
B157FAA423264AE900EBFBD4 /* SettingsDiscoveryThreePidDetailsViewController.storyboard in Resources */,
@ -5628,6 +5768,7 @@
B1B558D620EF768F00210D55 /* RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.xib in Resources */,
B1B5593720EF7BAC00210D55 /* TableViewCellWithCheckBoxAndLabel.xib in Resources */,
B190F55B22CE35FD00AEB493 /* EditHistoryHeaderView.xib in Resources */,
EC31F016251B53BC00D407DA /* RoomInfoBasicView.xib in Resources */,
EC1CA86524C1DEC400DE9EBF /* EnterPinCodeViewController.storyboard in Resources */,
B1B5579020EF568D00210D55 /* GroupTableViewCell.xib in Resources */,
B142317B22CCFA2000FFA96A /* EditHistoryCell.xib in Resources */,
@ -5773,6 +5914,7 @@
B1B5572B20EE6C4D00210D55 /* RoomMemberDetailsViewController.xib in Resources */,
B1D4752C21EE52C30067973F /* KeyBackupSetupIntroViewController.storyboard in Resources */,
B1B558C620EF768F00210D55 /* RoomIncomingEncryptedAttachmentBubbleCell.xib in Resources */,
B12676872523E4D100BE6B98 /* SecretsResetViewController.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -6012,11 +6154,16 @@
EC85D7462477E5F7002C44C9 /* NotificationService.swift in Sources */,
32FD755424D074C700BA7B37 /* CommonConfiguration.swift in Sources */,
EC9A3EC624E1632C00A8CFAE /* PushNotificationStore.swift in Sources */,
EC31F0952521FC4600D407DA /* PinCodePreferences.swift in Sources */,
32FD757424D2BEF700BA7B37 /* InfoPlist.swift in Sources */,
EC31F09C2524AE1400D407DA /* BiometricsAuthenticationPresenter.swift in Sources */,
EC85D752247C0F52002C44C9 /* UNUserNotificationCenter.swift in Sources */,
EC9A3EC724E1634100A8CFAE /* KeyValueStore.swift in Sources */,
32FD757A24D2C9BA00BA7B37 /* Bundle.swift in Sources */,
EC31F0962521FC5300D407DA /* Strings.swift in Sources */,
EC31F0972521FC6300D407DA /* Images.swift in Sources */,
EC9A3EC824E1634800A8CFAE /* KeychainStore.swift in Sources */,
EC31F0942521FC3700D407DA /* LocalAuthenticationService.swift in Sources */,
32FD755B24D15C7A00BA7B37 /* Configurable.swift in Sources */,
EC85D755247C0F84002C44C9 /* Constants.swift in Sources */,
);
@ -6029,6 +6176,7 @@
EC711B7B24A63B37008F830C /* SecretsSetupRecoveryKeyCoordinator.swift in Sources */,
B1B557D120EF5E3500210D55 /* MediaAlbumTableCell.m in Sources */,
32607D71243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewState.swift in Sources */,
EC51E7A92514D2E100AAE7DB /* RoomInfoListViewModelType.swift in Sources */,
324A2053225FC571004FE8B0 /* DeviceVerificationIncomingViewModel.swift in Sources */,
B1B557A120EF58AD00210D55 /* ContactTableViewCell.m in Sources */,
B1CE83DE2422817200D07506 /* KeyVerificationVerifyBySASViewModelType.swift in Sources */,
@ -6063,6 +6211,7 @@
EC1CA86924C1DEC400DE9EBF /* SetPinCoordinator.swift in Sources */,
B1B5574B20EE6C4D00210D55 /* MediaAlbumContentViewController.m in Sources */,
ECFBD5CC250A7AAF00DD5F5A /* DirectoryRoomTableViewCell.swift in Sources */,
EC49F5F92515016F003894A6 /* RoomInfoBasicViewData.swift in Sources */,
B1B5598820EFC3E000210D55 /* WidgetManager.m in Sources */,
B1DB4F0E22316FFF0065DBFA /* UserNameColorGenerator.swift in Sources */,
B157FAA123264AE900EBFBD4 /* SettingsDiscoveryThreePidDetailsCoordinatorType.swift in Sources */,
@ -6087,6 +6236,7 @@
B1B5574420EE6C4D00210D55 /* CallViewController.m in Sources */,
EC1CA86024C1DEC400DE9EBF /* EnterPinCodeViewAction.swift in Sources */,
ECFBD5E0250B684E00DD5F5A /* ChooseAvatarTableViewCell.swift in Sources */,
EC31F09A2524A60E00D407DA /* BiometricsAuthenticationPresenter.swift in Sources */,
32FD757624D2C9BA00BA7B37 /* Bundle.swift in Sources */,
B12D7A0023E2462200FACEDC /* UserVerificationStartCoordinatorType.swift in Sources */,
EC711B9324A63B37008F830C /* SecretsRecoveryWithKeyViewController.swift in Sources */,
@ -6106,10 +6256,12 @@
B1A68593229E807A00D6C09A /* RoomBubbleCellLayout.swift in Sources */,
ECFBD603250FA98200DD5F5A /* RoomCreationModalCoordinatorBridgePresenter.swift in Sources */,
B1B558F420EF768F00210D55 /* RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.m in Sources */,
B12676882523E4D100BE6B98 /* SecretsResetViewState.swift in Sources */,
B1B5572320EE6C4D00210D55 /* AttachmentsViewController.m in Sources */,
B18DEDDD2433967C0075FEF7 /* KeyVerificationFlow.swift in Sources */,
F083BDEE1E7009ED00A9B29C /* MXRoom+Riot.m in Sources */,
328E410624CB168500DC4490 /* AppConfiguration.swift in Sources */,
B12676842523E4D100BE6B98 /* SecretsResetViewModelType.swift in Sources */,
EC711B9624A63B37008F830C /* SecretsRecoveryWithKeyViewState.swift in Sources */,
B120863722EF375F001F89E0 /* ReactionHistoryBridgeCoordinatorPresenter.swift in Sources */,
EC711B9224A63B37008F830C /* SecretsRecoveryWithKeyViewModel.swift in Sources */,
@ -6133,11 +6285,14 @@
B1B5572F20EE6C4D00210D55 /* ReadReceiptsViewController.m in Sources */,
B1BD71BC238E8F9600BA92E2 /* WidgetPermissionViewController.swift in Sources */,
B1B558CB20EF768F00210D55 /* RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.m in Sources */,
B10A3E9824FE86AF007C380F /* SplitViewCoordinatorType.swift in Sources */,
B11291EA238D35590077B478 /* SlidingModalPresentable.swift in Sources */,
B157FAA823264BED00EBFBD4 /* SettingsDiscoveryThreePidDetailsCoordinatorBridgePresenter.swift in Sources */,
B169330B20F3CA3A00746532 /* Contact.m in Sources */,
B1A5B33E227ADF2A004CBA85 /* UIImage.swift in Sources */,
EC51E7AC2514D2E100AAE7DB /* RoomInfoListCoordinatorType.swift in Sources */,
B1D4752A21EE52B10067973F /* KeyBackupSetupIntroViewController.swift in Sources */,
B10A3E9424FE8254007C380F /* AppCoordinatorType.swift in Sources */,
B108931F23AB80EF00802670 /* KeyVerificationIncomingRequestApprovalBubbleCell.swift in Sources */,
EC51E7922510C0A500AAE7DB /* SpanningSlidingModalContainerView.swift in Sources */,
B1CE83D42422817200D07506 /* KeyVerificationVerifiedViewController.swift in Sources */,
@ -6145,6 +6300,7 @@
B14F143422144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyViewAction.swift in Sources */,
B1098BF621ECFE65000DDA48 /* KeyBackupSetupPassphraseCoordinator.swift in Sources */,
B1B558C320EF768F00210D55 /* RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.m in Sources */,
B10A3E9D24FE88CB007C380F /* RootRouterType.swift in Sources */,
B1B9DEDC22E9B7440065E677 /* SerializationServiceType.swift in Sources */,
B110872521F098F0003554A5 /* ActivityIndicatorPresenter.swift in Sources */,
32242F1521E8FBA900725742 /* DarkTheme.swift in Sources */,
@ -6175,9 +6331,12 @@
3291DC8D23E0BFF10009732F /* SecurityViewController.m in Sources */,
B18DEDD4243377C10075FEF7 /* KeyVerificationSelfVerifyWaitViewModelType.swift in Sources */,
B1C45A88232A8C2600165425 /* SettingsIdentityServerViewState.swift in Sources */,
B1C782302500EAF500337EB9 /* TabBarCoordinatorType.swift in Sources */,
B1C782322500F96700337EB9 /* SplitViewPresentable.swift in Sources */,
B14F142F22144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyViewModelType.swift in Sources */,
32DB557822FDADE50016329E /* ServiceTermsModalScreenViewState.swift in Sources */,
B1B558E120EF768F00210D55 /* RoomMembershipCollapsedBubbleCell.m in Sources */,
EC51E7AB2514D2E100AAE7DB /* RoomInfoListViewState.swift in Sources */,
B1B5571A20EE6C4D00210D55 /* SettingsViewController.m in Sources */,
B1CE9EFD22148703000FAE6A /* SignOutAlertPresenter.swift in Sources */,
32F6B9692270623100BBA352 /* KeyVerificationDataLoadingCoordinator.swift in Sources */,
@ -6206,6 +6365,7 @@
EC711B7424A63B37008F830C /* SecretsSetupRecoveryKeyViewModelType.swift in Sources */,
B14F143122144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyViewState.swift in Sources */,
32DB557F22FDADE50016329E /* ServiceTermsModalScreenCoordinator.swift in Sources */,
EC31F014251B53AD00D407DA /* RoomInfoBasicView.swift in Sources */,
EC1CA85F24C1DEC400DE9EBF /* EnterPinCodeViewModelType.swift in Sources */,
B1098C1121ED07E4000DDA48 /* NavigationRouterType.swift in Sources */,
B1B5573D20EE6C4D00210D55 /* WebViewViewController.m in Sources */,
@ -6216,6 +6376,7 @@
B1B5594520EF7BD000210D55 /* TableViewCellWithCollectionView.m in Sources */,
B1A6C109238828A6002882FD /* SlidingModalPresentationDelegate.swift in Sources */,
ECAE7AEE24EFDD1F002FA813 /* MXSessionState.swift in Sources */,
EC31F012251B4DBD00D407DA /* RoomInfoListViewData.swift in Sources */,
32DB557722FDADE50016329E /* ServiceTermsModalCoordinator.swift in Sources */,
ECF57A4B25090C23004BBF9D /* EnterNewRoomDetailsViewModel.swift in Sources */,
B185145B24B8C98200EE19EA /* MajorUpdateViewController.swift in Sources */,
@ -6248,6 +6409,7 @@
B1D4752721EE4E630067973F /* KeyboardAvoider.swift in Sources */,
B1D4752821EE4E630067973F /* KeyboardNotification.swift in Sources */,
B1D1BDA622BBAFB500831367 /* ReactionsMenuView.swift in Sources */,
EC51E7AD2514D2E100AAE7DB /* RoomInfoListCoordinator.swift in Sources */,
EC711B4624A63B13008F830C /* MXRecoveryService.swift in Sources */,
EC1CA86C24C1DEC400DE9EBF /* SetPinCoordinatorType.swift in Sources */,
EC1CA86324C1DEC400DE9EBF /* EnterPinCodeCoordinatorType.swift in Sources */,
@ -6277,6 +6439,7 @@
B142317A22CCFA2000FFA96A /* EditHistoryCell.swift in Sources */,
ECF57A50250913E4004BBF9D /* MXKTableViewCellWithLabelAndSwitch.swift in Sources */,
B1DCC62622E60CC600625807 /* EmojiItem.swift in Sources */,
B10A3E9324FE8254007C380F /* AppCoordinator.swift in Sources */,
B1B5572A20EE6C4D00210D55 /* RoomMemberDetailsViewController.m in Sources */,
EC3B066C24AC6ADE000DF9BF /* CrossSigningSetupBannerCell.swift in Sources */,
ECF57A4E25090C23004BBF9D /* EnterNewRoomDetailsViewModelType.swift in Sources */,
@ -6287,6 +6450,7 @@
B1DCC63922E85E9A00625807 /* EmojiMartStore.swift in Sources */,
B10A3E9024FE4368007C380F /* ElementViewController.swift in Sources */,
B1B5590620EF768F00210D55 /* RoomMembershipCollapsedWithPaginationTitleBubbleCell.m in Sources */,
EC51E7AE2514D2E100AAE7DB /* RoomInfoListViewModel.swift in Sources */,
B139C21D21FE5BF500BB68EC /* KeyBackupRecoverFromPassphraseViewModelType.swift in Sources */,
B157FA9F23264AE900EBFBD4 /* SettingsDiscoveryThreePidDetailsCoordinator.swift in Sources */,
B1CE83D92422817200D07506 /* KeyVerificationVerifyByScanningViewAction.swift in Sources */,
@ -6299,6 +6463,7 @@
B1C45A86232A8C2600165425 /* SettingsIdentityServerViewModelType.swift in Sources */,
F083BE031E7009ED00A9B29C /* EventFormatter.m in Sources */,
B157FAA623264AE900EBFBD4 /* SettingsDiscoveryThreePidDetailsViewController.swift in Sources */,
B126768A2523E4D100BE6B98 /* SecretsResetViewModel.swift in Sources */,
B1DCC62422E60CA900625807 /* EmojiPickerCategoryViewData.swift in Sources */,
B1550FCB2420E8F500CE097B /* QRCodeReaderViewController.swift in Sources */,
324A2056225FC571004FE8B0 /* DeviceVerificationIncomingCoordinator.swift in Sources */,
@ -6313,6 +6478,7 @@
B1B558E020EF768F00210D55 /* RoomOutgoingTextMsgBubbleCell.m in Sources */,
EC711B7824A63B37008F830C /* SecretsSetupRecoveryKeyViewModel.swift in Sources */,
B1C562E3228C7C8D0037F12A /* RoomContextualMenuPresenter.swift in Sources */,
B12676862523E4D100BE6B98 /* SecretsResetCoordinatorType.swift in Sources */,
EC85D7182477DCD7002C44C9 /* KeyVerificationScanConfirmationViewModelType.swift in Sources */,
ECF57A5E2509265A004BBF9D /* InsettedTextField.swift in Sources */,
B1B5593C20EF7BAC00210D55 /* TableViewCellWithCheckBoxes.m in Sources */,
@ -6329,7 +6495,9 @@
B1BEE71423DF2ACF0003A4CB /* UserVerificationCoordinatorType.swift in Sources */,
B1B5596F20EFA85D00210D55 /* EncryptionInfoView.m in Sources */,
ECFBD5D1250A7AAF00DD5F5A /* ShowDirectoryViewController.swift in Sources */,
B12676892523E4D100BE6B98 /* SecretsResetViewAction.swift in Sources */,
B1B5573820EE6C4D00210D55 /* GroupParticipantsViewController.m in Sources */,
EC51E7B02514D2E100AAE7DB /* RoomInfoCoordinatorType.swift in Sources */,
3232ABAB225730E100AD6A5C /* KeyVerificationCoordinator.swift in Sources */,
B1BEE73B23DF44A60003A4CB /* UserVerificationSessionsStatusCoordinator.swift in Sources */,
B1B5583E20EF6E7F00210D55 /* GroupRoomTableViewCell.m in Sources */,
@ -6344,6 +6512,7 @@
B1B9DEDA22E9B7350065E677 /* SerializationService.swift in Sources */,
B1B5572520EE6C4D00210D55 /* RoomMessagesSearchViewController.m in Sources */,
B197B7C6243DE947005ABBF3 /* EncryptionTrustLevelBadgeImageHelper.swift in Sources */,
EC51E7A82514D2E100AAE7DB /* RoomInfoListViewController.swift in Sources */,
B12D79FD23E2462200FACEDC /* UserVerificationStartViewModelType.swift in Sources */,
B1C543AE23A286A000DCA1FA /* KeyVerificationRequestStatusBubbleCell.swift in Sources */,
B139C22121FE5D9D00BB68EC /* KeyBackupRecoverFromPassphraseViewState.swift in Sources */,
@ -6360,8 +6529,10 @@
B1DCC63722E8541700625807 /* EmojiStore.swift in Sources */,
3232ABA6225730E100AD6A5C /* DeviceVerificationStartViewController.swift in Sources */,
B16932EA20F3C39000746532 /* UnifiedSearchRecentsDataSource.m in Sources */,
B10A3E9924FE86AF007C380F /* SplitViewCoordinator.swift in Sources */,
B1BEE72A23DF38B20003A4CB /* UserVerificationSessionStatusCell.swift in Sources */,
B1C45A8A232A8C2600165425 /* SettingsIdentityServerCoordinatorBridgePresenter.swift in Sources */,
B1C7822F2500EAF500337EB9 /* TabBarCoordinator.swift in Sources */,
B1B557DE20EF5FBB00210D55 /* FilesSearchTableViewCell.m in Sources */,
B1B5574020EE6C4D00210D55 /* SegmentedViewController.m in Sources */,
ECF57A4C25090C23004BBF9D /* EnterNewRoomDetailsViewAction.swift in Sources */,
@ -6397,6 +6568,7 @@
ECDC15F224AF41D2003437CF /* FormattedBodyParser.swift in Sources */,
B1B5577E20EE84BF00210D55 /* IncomingCallView.m in Sources */,
B1CE83E22422817200D07506 /* KeyVerificationVerifyBySASViewState.swift in Sources */,
EC51E7AF2514D2E100AAE7DB /* RoomInfoListViewAction.swift in Sources */,
B1DCC62822E60CE300625807 /* EmojiCategory.swift in Sources */,
B14084CC23BF9DE90010F692 /* KeyVerificationConclusionWithPaginationTitleBubbleCell.swift in Sources */,
B1CE83D62422817200D07506 /* KeyVerificationVerifyByScanningCoordinator.swift in Sources */,
@ -6411,6 +6583,7 @@
B1DCC61D22E5E17100625807 /* EmojiPickerViewModelType.swift in Sources */,
B1B5574120EE6C4D00210D55 /* RecentsViewController.m in Sources */,
B1D250D82118AA0A000F4E93 /* RoomPredecessorBubbleCell.m in Sources */,
B12676832523E4D100BE6B98 /* SecretsResetCoordinator.swift in Sources */,
B1B5577120EE702800210D55 /* StickerPickerViewController.m in Sources */,
EC711B7624A63B37008F830C /* SecretsSetupRecoveryKeyViewState.swift in Sources */,
32FDC1CD2386CD390084717A /* RiotSettingIntegrationProvisioning.swift in Sources */,
@ -6449,6 +6622,7 @@
EC1CA89A24C9C9A200DE9EBF /* SetupBiometricsCoordinatorType.swift in Sources */,
32A6001722C661100042C1D9 /* EditHistoryViewController.swift in Sources */,
B1098BFA21ECFE65000DDA48 /* KeyBackupSetupPassphraseViewModel.swift in Sources */,
EC51E7A62514D2E100AAE7DB /* RoomInfoCoordinatorBridgePresenter.swift in Sources */,
EC1CA87524C8259700DE9EBF /* KeychainStore.swift in Sources */,
B1B5575220EE6C4D00210D55 /* RoomKeyRequestViewController.m in Sources */,
32A6001A22C661100042C1D9 /* EditHistoryCoordinator.swift in Sources */,
@ -6568,11 +6742,13 @@
B14F143222144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyCoordinator.swift in Sources */,
B110872621F098F0003554A5 /* ActivityIndicatorView.swift in Sources */,
ECAE7AE924EC1888002FA813 /* Row.swift in Sources */,
B12676852523E4D100BE6B98 /* SecretsResetViewController.swift in Sources */,
B1CE83E02422817200D07506 /* KeyVerificationVerifyBySASViewController.swift in Sources */,
B19EFA3921F8BB2C00FC070E /* KeyBackupRecoverCoordinatorType.swift in Sources */,
B1C3360322F1ED600021BA8D /* MediaPickerCoordinator.swift in Sources */,
B1E5368D21FB7245001F3AFF /* KeyBackupRecoverFromPassphraseViewController.swift in Sources */,
EC711B8924A63B37008F830C /* SecretsRecoveryWithPassphraseViewModel.swift in Sources */,
B10A3E9F24FFC3E6007C380F /* PlaceholderDetailViewController.swift in Sources */,
B1963B3822933BC800CBA17F /* AutosizedCollectionView.swift in Sources */,
EC711B7A24A63B37008F830C /* SecretsSetupRecoveryKeyViewAction.swift in Sources */,
B12D79FB23E2462200FACEDC /* UserVerificationStartCoordinator.swift in Sources */,
@ -6592,6 +6768,7 @@
B1B558D320EF768F00210D55 /* RoomOutgoingEncryptedTextMsgBubbleCell.m in Sources */,
B1B5576F20EE702800210D55 /* IntegrationManagerViewController.m in Sources */,
32FD756424D2AD5100BA7B37 /* BuildSettings.swift in Sources */,
EC51E7A72514D2E100AAE7DB /* RoomInfoCoordinator.swift in Sources */,
B1B557AC20EF5A6D00210D55 /* DeviceView.m in Sources */,
3281BCF72201FA4200F4A383 /* UIControl.swift in Sources */,
B16932EE20F3C3C900746532 /* FilesSearchCellData.m in Sources */,
@ -6657,7 +6834,7 @@
ECFBD5D6250A7AAF00DD5F5A /* ShowDirectoryViewAction.swift in Sources */,
EC711BB124A63B58008F830C /* SecureBackupBannerPreferences.swift in Sources */,
ECF57A4625090C23004BBF9D /* CreateRoomCoordinator.swift in Sources */,
ECFBD5DC250A82B200DD5F5A /* TableViewHeaderFooterView.swift in Sources */,
ECFBD5DC250A82B200DD5F5A /* TextViewTableViewHeaderFooterView.swift in Sources */,
B1BEE73723DF44A60003A4CB /* UserVerificationSessionsStatusViewState.swift in Sources */,
B108932823ABEE6800802670 /* BubbleCellReadReceiptsDisplayable.swift in Sources */,
B1B558FF20EF768F00210D55 /* RoomIncomingTextMsgBubbleCell.m in Sources */,
@ -6677,6 +6854,7 @@
B1B9DEEC22EB34EF0065E677 /* ReactionHistoryViewModelType.swift in Sources */,
B157FAA523264AE900EBFBD4 /* SettingsDiscoveryThreePidDetailsViewModel.swift in Sources */,
EC711B8624A63B37008F830C /* SecretsRecoveryWithPassphraseCoordinatorType.swift in Sources */,
B10A3E9C24FE88CB007C380F /* RootRouter.swift in Sources */,
B1C562E8228C7CF20037F12A /* ContextualMenuItemView.swift in Sources */,
B14F143022144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyCoordinatorType.swift in Sources */,
B1E5368921FB1E20001F3AFF /* UIButton.swift in Sources */,
@ -7092,7 +7270,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1.0.12;
CURRENT_PROJECT_VERSION = 1.0.13;
DEFINES_MODULE = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
@ -7112,7 +7290,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 1.0.12;
MARKETING_VERSION = 1.0.13;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@ -7151,7 +7329,7 @@
CODE_SIGN_IDENTITY = "iPhone Distribution";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
COPY_PHASE_STRIP = YES;
CURRENT_PROJECT_VERSION = 1.0.12;
CURRENT_PROJECT_VERSION = 1.0.13;
DEFINES_MODULE = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@ -7164,7 +7342,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 1.0.12;
MARKETING_VERSION = 1.0.13;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="H1p-Uh-vWS">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097.2" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="H1p-Uh-vWS">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
@ -261,7 +261,7 @@
<!--Master Tab Bar Controller-->
<scene sceneID="iBe-Y5-gBt">
<objects>
<tabBarController id="xaQ-tG-rlO" customClass="MasterTabBarController" sceneMemberID="viewController">
<tabBarController storyboardIdentifier="MasterTabBarController" id="xaQ-tG-rlO" customClass="MasterTabBarController" sceneMemberID="viewController">
<navigationItem key="navigationItem" id="m6O-wq-yrc">
<barButtonItem key="leftBarButtonItem" image="settings_icon" id="QSE-cg-V2m">
<userDefinedRuntimeAttributes>
@ -288,15 +288,12 @@
<connections>
<outlet property="searchBarButtonIem" destination="pud-Fh-Usd" id="DiH-Re-nZE"/>
<outlet property="settingsBarButtonItem" destination="QSE-cg-V2m" id="N6b-Ju-w9g"/>
<segue destination="vC3-pB-5Vb" kind="showDetail" identifier="showRoomDetails" id="tk8-vF-K4T"/>
<segue destination="ZlD-EU-ncw" kind="presentation" identifier="showAuth" modalPresentationStyle="fullScreen" id="fpJ-zM-Qpo"/>
<segue destination="pBa-To-3YT" kind="relationship" relationship="viewControllers" id="Sfs-mh-GOz"/>
<segue destination="vC3-pB-5Vb" kind="showDetail" identifier="showContactDetails" id="p4M-yR-DLA"/>
<segue destination="HnD-LA-psC" kind="relationship" relationship="viewControllers" id="zON-Qp-EVq"/>
<segue destination="IGB-jr-yFz" kind="relationship" relationship="viewControllers" id="CeF-yL-aO0"/>
<segue destination="HPQ-zg-lZR" kind="relationship" relationship="viewControllers" id="y12-eg-vhO"/>
<segue destination="SLx-Wj-p7E" kind="relationship" relationship="viewControllers" id="MLn-VT-30W"/>
<segue destination="vC3-pB-5Vb" kind="showDetail" identifier="showGroupDetails" id="fIR-e3-ssz"/>
</connections>
</tabBarController>
<placeholder placeholderIdentifier="IBFirstResponder" id="k1S-FF-3Zu" userLabel="First Responder" sceneMemberID="firstResponder"/>
@ -342,7 +339,7 @@
<!--RecentsSplitVC-->
<scene sceneID="Nki-YV-4Qg">
<objects>
<splitViewController title="RecentsSplitVC" id="H1p-Uh-vWS" customClass="RiotSplitViewController" sceneMemberID="viewController">
<splitViewController storyboardIdentifier="RiotSplitViewController" title="RecentsSplitVC" id="H1p-Uh-vWS" customClass="RiotSplitViewController" sceneMemberID="viewController">
<toolbarItems/>
<navigationItem key="navigationItem" id="EB5-8V-irH"/>
<connections>
@ -422,10 +419,10 @@
</objects>
<point key="canvasLocation" x="-1375" y="-1121"/>
</scene>
<!--View Controller-->
<!--Placeholder Detail View Controller-->
<scene sceneID="2wP-Cu-Wca">
<objects>
<viewController storyboardIdentifier="EmptyDetailsViewControllerStoryboardId" id="Cpr-Tz-Az0" sceneMemberID="viewController">
<viewController storyboardIdentifier="EmptyDetailsViewControllerStoryboardId" id="Cpr-Tz-Az0" customClass="PlaceholderDetailViewController" customModule="Riot" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="yS4-RU-AsN"/>
<viewControllerLayoutGuide type="bottom" id="VKG-pW-vMU"/>
@ -434,8 +431,12 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="logo" translatesAutoresizingMaskIntoConstraints="NO" id="6LG-qc-7jf">
<rect key="frame" x="127.5" y="283" width="120" height="101"/>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="launch_screen_logo" translatesAutoresizingMaskIntoConstraints="NO" id="6LG-qc-7jf">
<rect key="frame" x="127.5" y="273.5" width="120" height="120"/>
<constraints>
<constraint firstAttribute="width" secondItem="6LG-qc-7jf" secondAttribute="height" multiplier="1:1" id="4Qy-7P-CuE"/>
<constraint firstAttribute="width" constant="120" id="E2Y-gX-itg"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
@ -445,6 +446,9 @@
</constraints>
</view>
<navigationItem key="navigationItem" id="c9s-dM-eEg"/>
<connections>
<outlet property="logoImageView" destination="6LG-qc-7jf" id="vLR-KE-0aH"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="pZm-ap-zdK" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
@ -590,15 +594,14 @@
</scene>
</scenes>
<inferredMetricsTieBreakers>
<segue reference="Tfl-tq-LQp"/>
<segue reference="fIR-e3-ssz"/>
<segue reference="mhb-l9-pM3"/>
<segue reference="f5u-Y1-7nt"/>
<segue reference="vCz-dl-6xQ"/>
<segue reference="cUw-vU-gJq"/>
</inferredMetricsTieBreakers>
<resources>
<image name="integrations_icon" width="24" height="24"/>
<image name="logo" width="120" height="101"/>
<image name="launch_screen_logo" width="240" height="240"/>
<image name="search_icon" width="24" height="24"/>
<image name="settings_icon" width="24" height="24"/>
<image name="tab_favourites" width="24" height="24"/>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View file

@ -0,0 +1,26 @@
{
"images" : [
{
"filename" : "secrets_reset_warning.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "secrets_reset_warning@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "secrets_reset_warning@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 898 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -326,7 +326,7 @@
"settings_crypto_device_id" = "\nSitzungs-ID: ";
"settings_crypto_blacklist_unverified_devices" = "Verschlüssele nur zu verifizierten Sitzungen";
"room_details_people" = "Mitglieder";
"room_details_files" = "Dateien";
"room_details_files" = "Uploads";
"room_details_mute_notifs" = "Benachrichtigungen stummschalten";
"room_details_access_section_no_address_warning" = "Um einen Raum zu betreten, muss er eine Adresse haben";
"room_details_access_section_directory_toggle" = "Zeige alle Räume in diesem Verzeichnis";
@ -1095,7 +1095,7 @@
"key_verification_verify_qr_code_scan_code_action" = "Scanne Code des Gegenübers";
"key_verification_verify_qr_code_cannot_scan_action" = "Scannen nicht möglich?";
"key_verification_verify_qr_code_start_emoji_action" = "Verifizierung durch Emojis";
"key_verification_verify_qr_code_other_scan_my_code_title" = "Hat dein Gegenüber erfolgreich den QR-Code gescannt?";
"key_verification_verify_qr_code_other_scan_my_code_title" = "Hat dein Gegenüber den QR-Code erfolgreich gescannt?";
"key_verification_verify_qr_code_scan_other_code_success_title" = "Code erfolgreich überprüft!";
// Scanning
"key_verification_scan_confirmation_scanning_title" = "Fast da! Warten auf Bestätigung…";
@ -1152,7 +1152,7 @@
"major_update_information" = "Wir sind begeistert unsere Namensänderung mitteilen zu können! Deine App ist auf dem neusten Stand und du bist mit deinem Account angemeldet.";
"major_update_learn_more_action" = "Mehr erfahren";
"major_update_done_action" = "Verstanden";
"pin_protection_choose_pin" = "Nutze eine PIN für mehr Sicherheit";
"pin_protection_choose_pin" = "Erstelle eine PIN für mehr Sicherheit";
"pin_protection_confirm_pin" = "Bestätige deinen PIN";
"pin_protection_confirm_pin_to_disable" = "Bestätige PIN um die PIN zu deaktivieren";
"pin_protection_enter_pin" = "Gib deine PIN ein";
@ -1181,3 +1181,32 @@
"biometrics_cant_unlocked_alert_message_login" = "Erneut anmelden";
"biometrics_cant_unlocked_alert_message_retry" = "Erneut probieren";
"device_verification_self_verify_wait_recover_secrets_checking_availability" = "Nach anderen Überprüfungsfunktionen suchen ...";
"joined" = "Beigetreten";
"switch" = "Ändern";
"more" = "Mehr";
"pin_protection_choose_pin_welcome_after_login" = "Willkommen zurück.";
"pin_protection_choose_pin_welcome_after_register" = "Willkommen.";
"pin_protection_not_allowed_pin" = "Aus Sicherheitsgründen ist diese PIN nicht verfügbar. Bitte versuche es mit einer anderen PIN";
"pin_protection_explanatory" = "PINs helfen dein Profil, deine Nachrichten und Kontakte so zu sichern, dass nur du Zugriff auf sie hast.";
"searchable_directory_create_new_room" = "Erstelle einen neuen Raum";
"searchable_directory_x_network" = "%@ Netzwerk";
"searchable_directory_search_placeholder" = "Name oder ID";
"create_room_title" = "Neuer Raum";
"create_room_section_header_name" = "Raumname";
"create_room_placeholder_name" = "Name";
"create_room_section_header_topic" = "Raum-Thema (optional)";
"create_room_placeholder_topic" = "Thema";
"create_room_section_header_encryption" = "Raum-Verschlüsselung";
"create_room_enable_encryption" = "Verschlüsselung aktivieren";
"create_room_section_footer_encryption" = "Verschlüsselung kann im Nachhinein nicht deaktiviert werden.";
"create_room_section_header_type" = "Raum-Typ";
"create_room_type_private" = "Privater Raum";
"create_room_type_public" = "Öffentlicher Raum";
"create_room_section_footer_type" = "Personen können einen privaten Raum nur mit Einladung betreten.";
"create_room_show_in_directory" = "Zeige den Raum im Raum-Verzeichnis";
"create_room_section_header_address" = "Raum-Adresse";
"create_room_placeholder_address" = "#testraum:matrix.org";
"room_info_list_room_encrypted" = "Nachrichten in diesem Raum sind Ende-zu-Ende verschlüsselt";
"room_info_list_one_member" = "1 Mitglied";
"room_info_list_several_members" = "%@ Mitglieder";
"room_info_list_section_other" = "Sonstige";

View file

@ -67,6 +67,8 @@
/* New message indicator on a room */
"MESSAGE_IN_X" = "Message in %@";
"MESSAGE_PROTECTED" = "New Message";
/** Coalesced messages **/
/* Multiple unread messages in a room */

View file

@ -228,13 +228,16 @@
"room_participants_one_participant" = "1 participant";
"room_participants_multi_participants" = "%d participants";
"room_participants_leave_prompt_title" = "Leave room";
"room_participants_leave_prompt_title_for_dm" = "Leave";
"room_participants_leave_prompt_msg" = "Are you sure you want to leave the room?";
"room_participants_leave_prompt_msg_for_dm" = "Are you sure you want to leave?";
"room_participants_remove_prompt_title" = "Confirmation";
"room_participants_remove_prompt_msg" = "Are you sure you want to remove %@ from this chat?";
"room_participants_remove_third_party_invite_prompt_msg" = "Are you sure you want to revoke this invite?";
"room_participants_invite_prompt_title" = "Confirmation";
"room_participants_invite_prompt_msg" = "Are you sure you want to invite %@ to this chat?";
"room_participants_filter_room_members" = "Filter room members";
"room_participants_filter_room_members_for_dm" = "Filter members";
"room_participants_invite_another_user" = "Search / invite by User ID, Name or email";
"room_participants_invite_malformed_id_title" = "Invite Error";
"room_participants_invite_malformed_id" = "Malformed ID. Should be an email address or a Matrix ID like '@localpart:domain'";
@ -276,7 +279,9 @@
"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_not_encrypted_for_dm" = "Messages here 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_participants_security_information_room_encrypted_for_dm" = "Messages here 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 %@";
@ -649,22 +654,29 @@
// Room Details
"room_details_title" = "Room Details";
"room_details_title_for_dm" = "Details";
"room_details_people" = "Members";
"room_details_files" = "Files";
"room_details_files" = "Uploads";
"room_details_settings" = "Settings";
"room_details_photo" = "Room Photo";
"room_details_photo_for_dm" = "Photo";
"room_details_room_name" = "Room Name";
"room_details_room_name_for_dm" = "Name";
"room_details_topic" = "Topic";
"room_details_favourite_tag" = "Favourite";
"room_details_low_priority_tag" = "Low priority";
"room_details_mute_notifs" = "Mute notifications";
"room_details_direct_chat" = "Direct Chat";
"room_details_access_section"="Who can access this room?";
"room_details_access_section_for_dm"="Who can access this?";
"room_details_access_section_invited_only"="Only people who have been invited";
"room_details_access_section_anyone_apart_from_guest"="Anyone who knows the room's link, apart from guests";
"room_details_access_section_anyone_apart_from_guest_for_dm"="Anyone who knows the link, apart from guests";
"room_details_access_section_anyone"="Anyone who knows the room's link, including guests";
"room_details_access_section_anyone_for_dm"="Anyone who knows the link, including guests";
"room_details_access_section_no_address_warning" = "To link to a room it must have an address";
"room_details_access_section_directory_toggle"="List this room in room directory";
"room_details_access_section_directory_toggle_for_dm"="List in room directory";
"room_details_history_section"="Who can read history?";
"room_details_history_section_anyone"="Anyone";
"room_details_history_section_members_only"="Members only (since the point in time of selecting this option)";
@ -674,6 +686,7 @@
"room_details_history_section_prompt_msg" = "Changes to who can read history will only apply to future messages in this room. The visibility of existing history will be unchanged.";
"room_details_addresses_section"="Addresses";
"room_details_no_local_addresses" = "This room has no local addresses";
"room_details_no_local_addresses_for_dm" = "This has no local addresses";
"room_details_new_address" = "Add new address";
"room_details_new_address_placeholder" = "Add new address (e.g. #foo%@)";
"room_details_addresses_invalid_address_prompt_title" = "Invalid alias format";
@ -687,9 +700,12 @@
"room_details_banned_users_section"="Banned users";
"room_details_advanced_section"="Advanced";
"room_details_advanced_room_id"="Room ID:";
"room_details_advanced_room_id_for_dm"="ID:";
"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_enabled_for_dm"="Encryption is enabled here";
"room_details_advanced_e2e_encryption_disabled"="Encryption is not enabled in this room.";
"room_details_advanced_e2e_encryption_disabled_for_dm"="Encryption is not enabled here.";
"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";
@ -1351,6 +1367,9 @@
// MARK: - Secrets recovery
"secrets_recovery_reset_action_part_1" = "Forgot or lost all recovery options? ";
"secrets_recovery_reset_action_part_2" = "Reset everything";
// Recover with passphrase
"secrets_recovery_with_passphrase_title" = "Recovery Passphrase";
@ -1406,6 +1425,15 @@
"key_backup_setup_passphrase_confirm_passphrase_valid" = "Great!";
"key_backup_setup_passphrase_confirm_passphrase_invalid" = "Passphrase doesnt match";
// MARK: - Secrets reset
"secrets_reset_title" = "Reset everything";
"secrets_reset_information" = "Only do this if you have no other device you can verify this device with.";
"secrets_reset_warning_title" = "If you reset everything";
"secrets_reset_warning_message" = "You will restart with no history, no messages, trusted devices or trusted users.";
"secrets_reset_reset_action" = "Reset";
"secrets_reset_authentication_message" = "Enter your account password to confirm";
// MARK: - Cross-signing
// Banner
@ -1422,7 +1450,9 @@
// MARK: - PIN Protection
"pin_protection_choose_pin" = "Choose a PIN for security";
"pin_protection_choose_pin_welcome_after_login" = "Welcome back.";
"pin_protection_choose_pin_welcome_after_register" = "Welcome.";
"pin_protection_choose_pin" = "Create a PIN for security";
"pin_protection_confirm_pin" = "Confirm your PIN";
"pin_protection_confirm_pin_to_disable" = "Confirm PIN to disable PIN";
"pin_protection_enter_pin" = "Enter your PIN";
@ -1437,6 +1467,9 @@
"pin_protection_settings_section_footer" = "To reset your PIN, you'll need to re-login and create a new one.";
"pin_protection_settings_enabled_forced" = "PIN enabled";
"pin_protection_settings_enable_pin" = "Enable PIN";
"pin_protection_not_allowed_pin" = "For security reasons, this PIN isnt available. Please try another PIN";
"pin_protection_explanatory" = "Setting up a PIN lets you protect data like messages and contacts, so only you can access them by entering the PIN at the start of the app.";
"pin_protection_kick_user_alert_message" = "Too many errors, you've been logged out";
// MARK: - Biometrics Protection
@ -1448,7 +1481,6 @@
"biometrics_setup_subtitle" = "Save yourself time";
"biometrics_desetup_title_x" = "Disable %@";
"biometrics_desetup_subtitle" = "";
"biometrics_desetup_disable_button_title_x" = "Disable %@";
"biometrics_usage_reason" = "Authentication is needed to access your app";
@ -1480,3 +1512,9 @@
"create_room_show_in_directory" = "Show the room in the directory";
"create_room_section_header_address" = "Room address";
"create_room_placeholder_address" = "#testroom:matrix.org";
// MARK: - Room Info
"room_info_list_one_member" = "1 member";
"room_info_list_several_members" = "%@ members";
"room_info_list_section_other" = "Other";

View file

@ -113,7 +113,7 @@
"room_participants_action_security_status_loading" = "Laeme…";
"room_participants_security_loading" = "Laeme…";
"room_participants_security_information_room_not_encrypted" = "See jututuba ei ole läbivalt krüptitud.";
"room_participants_security_information_room_encrypted" = "Sõnumid siis jututoas kasutavad läbivat krüptimist.\n\nSinu sõnumid on turvatud ning ainult sinul ja saaja(te)l on unikaalsed võtmed selliste sõnumite lugemiseks.";
"room_participants_security_information_room_encrypted" = "Sõnumid siin jututoas kasutavad läbivat krüptimist.\n\nSinu sõnumid on turvatud ning ainult sinul ja saaja(te)l on unikaalsed võtmed selliste sõnumite lugemiseks.";
// Chat
"room_jump_to_first_unread" = "Mine esimese lugemata sõnumi juurde";
// Room Details
@ -1140,3 +1140,33 @@
"secure_key_backup_setup_existing_backup_error_delete_it" = "Kustuta varukoopia";
"device_verification_self_verify_wait_recover_secrets_additional_information" = "Või kui sa ei saa neid kasutada, siis võid olemasolevas sessioonis";
"device_verification_self_verify_wait_recover_secrets_checking_availability" = "Kontrollin teiste verifikatsioonivõimaluste olemasolu ...";
"biometrics_desetup_subtitle" = "biometrics_desetup_subtitle";
"joined" = "Liikmed";
"switch" = "Vaheta";
"more" = "Veel";
"pin_protection_choose_pin_welcome_after_login" = "Tere tulemast tagasi.";
"pin_protection_choose_pin_welcome_after_register" = "Tere tulemast.";
"pin_protection_not_allowed_pin" = "Turvapõhjustel seda PIN-kooi ei saa kasutada. Palun vali mõnu muu PIN-kood";
"pin_protection_explanatory" = "PIN-kood aitab tagada, et vaid sina ise pääsed ligi oma profiilile, sõnumitele ja kontaktidele.";
"searchable_directory_create_new_room" = "Loo uus jututuba";
"searchable_directory_x_network" = "%@ võrk";
"searchable_directory_search_placeholder" = "Nimi või Matrix'i tunnus";
"create_room_title" = "Uus jututuba";
"create_room_section_header_name" = "Jututoa nimi";
"create_room_placeholder_name" = "Nimi";
"create_room_section_header_topic" = "Jututoa teema (valikuline)";
"create_room_placeholder_topic" = "Jututoa teema";
"create_room_section_header_encryption" = "Krüptimine jututoas";
"create_room_enable_encryption" = "Võta krüptimine kasutusele";
"create_room_section_footer_encryption" = "Krüptimist ei saa hiljem välja lülitada.";
"create_room_section_header_type" = "Jututoa tüüp";
"create_room_type_private" = "Omavaheline jututuba";
"create_room_type_public" = "Avalik jututuba";
"create_room_section_footer_type" = "Omavahelise jututoaga saab liituda vaid kutsega.";
"create_room_show_in_directory" = "Näita jututubade loendit";
"create_room_section_header_address" = "Jututoa aadress";
"create_room_placeholder_address" = "#torenimi:domeen.ee";
"room_info_list_room_encrypted" = "See jututuba on läbivalt krüptitud";
"room_info_list_one_member" = "1 liige";
"room_info_list_several_members" = "%@ liiget";
"room_info_list_section_other" = "Muud";

View file

@ -390,7 +390,7 @@
// Room Details
"room_details_title" = "Dettagli stanza";
"room_details_people" = "Membri";
"room_details_files" = "File";
"room_details_files" = "File caricati";
"room_details_settings" = "Impostazioni";
"room_details_photo" = "Immagine stanza";
"room_details_room_name" = "Nome stanza";
@ -1146,7 +1146,7 @@
"major_update_done_action" = "Capito";
"external_link_confirmation_title" = "Controlla bene questo collegamento";
"external_link_confirmation_message" = "Il collegamento %@ ti porterà in un altro sito: %@\n\nSei sicuro di voler continuare?";
"pin_protection_choose_pin" = "Scegli un PIN di sicurezza";
"pin_protection_choose_pin" = "Crea un PIN di sicurezza";
"pin_protection_confirm_pin" = "Conferma il PIN";
"pin_protection_confirm_pin_to_disable" = "Conferma il PIN per disattivarlo";
"pin_protection_enter_pin" = "Inserisci il tuo PIN";
@ -1174,3 +1174,33 @@
"biometrics_cant_unlocked_alert_message_x" = "Per sbloccare, usa %@ o riaccedi e attiva %@ di nuovo";
"biometrics_cant_unlocked_alert_message_login" = "Riaccedi";
"biometrics_cant_unlocked_alert_message_retry" = "Riprova";
"device_verification_self_verify_wait_recover_secrets_checking_availability" = "Controllo di altre possibilità di verifica...";
"joined" = "Entrato";
"switch" = "Cambia";
"more" = "Altro";
"pin_protection_choose_pin_welcome_after_login" = "Bentornato/a.";
"pin_protection_choose_pin_welcome_after_register" = "Benvenuti.";
"pin_protection_not_allowed_pin" = "Per motivi di sicurezza, questo PIN non è disponibile. Provane un altro";
"pin_protection_explanatory" = "I PIN aiutano a tenere sicuri il tuo profilo, i messaggi e i contatti, in modo che solo tu possa vederli.";
"searchable_directory_create_new_room" = "Crea una nuova stanza";
"searchable_directory_x_network" = "Rete %@";
"searchable_directory_search_placeholder" = "Nome o ID";
"create_room_title" = "Nuova stanza";
"create_room_section_header_name" = "Nome stanza";
"create_room_placeholder_name" = "Nome";
"create_room_section_header_topic" = "Argomento stanza (facoltativo)";
"create_room_placeholder_topic" = "Argomento";
"create_room_section_header_encryption" = "Crittografia stanza";
"create_room_enable_encryption" = "Attiva crittografia";
"create_room_section_footer_encryption" = "La crittografia non può essere disattivata in seguito.";
"create_room_section_header_type" = "Tipo stanza";
"create_room_type_private" = "Stanza privata";
"create_room_type_public" = "Stanza pubblica";
"create_room_section_footer_type" = "Le persone entrano in una stanza privata solo su invito.";
"create_room_show_in_directory" = "Mostra la stanza nell'elenco";
"create_room_section_header_address" = "Indirizzo stanza";
"create_room_placeholder_address" = "#stanzatest:matrix.org";
"room_info_list_room_encrypted" = "I messaggi in questa stanza sono cifrati end-to-end";
"room_info_list_one_member" = "1 membro";
"room_info_list_several_members" = "%@ membri";
"room_info_list_section_other" = "Altro";

View file

@ -132,7 +132,7 @@
"room_participants_ago" = "temu";
"room_participants_action_section_admin_tools" = "Narzędzia Administracyjne";
"room_participants_action_section_direct_chats" = "Rozmowy bezpośrednie";
"room_participants_action_section_devices" = "Urządzenia";
"room_participants_action_section_devices" = "Sesje";
"room_participants_action_invite" = "Zaproś";
"room_participants_action_leave" = "Opuść pokój";
"room_participants_action_remove" = "Usuń z pokoju";
@ -371,7 +371,7 @@
"room_participants_online" = "Dostępny(-a)";
"room_participants_offline" = "Niedostępny(-a)";
"room_participants_unknown" = "Nieznane";
"room_participants_action_section_other" = "Inny";
"room_participants_action_section_other" = "Opcje";
// Chat
"room_jump_to_first_unread" = "Przeskocz do pierwszej nieprzeczytanej wiadomości";
"room_new_message_notification" = "%d nowa wiadomość";
@ -803,3 +803,79 @@
"key_backup_setup_skip_alert_skip_action" = "Pomiń";
"key_backup_setup_intro_title" = "Nigdy nie trać zaszyfrowanych wiadomości";
"key_backup_setup_intro_info" = "Wiadomości w szyfrowanym pokoju są zabezpieczone przez end-to-end. Tylko Ty i rozmówca macie klucze, aby odczytać te wiadomości.\nWykonaj kopię zapasową kluczy, aby ich nie zgubić.";
"user_verification_session_details_trusted_title" = "Zaufany";
"user_verification_session_details_untrusted_title" = "Niezaufany";
"user_verification_session_details_information_trusted_current_user" = "Ta sesja jest zaufana dla bezpiecznego przesyłania wiadomości, ponieważ ją zweryfikowałeś:";
"skip" = "Pomiń";
"joined" = "Dołączył";
"switch" = "Zmień";
"more" = "Więcej";
// Accessibility
"accessibility_checkbox_label" = "pole wyboru";
// MARK: Clients
"client_desktop_name" = "Element Desktop";
"client_web_name" = "Element Web";
"client_ios_name" = "Element iOS";
"client_android_name" = "Element Android";
"room_participants_action_section_security" = "Bezpieczeństwo";
"room_participants_action_security_status_verified" = "Zweryfikowany";
"room_participants_action_security_status_verify" = "Zweryfikuj";
"room_participants_action_security_status_complete_security" = "Ustaw bezpieczeństwo";
"room_participants_action_security_status_warning" = "Ostrzeżenie";
"room_participants_action_security_status_loading" = "Ładowanie…";
"room_participants_security_loading" = "Ładowanie…";
"room_participants_security_information_room_not_encrypted" = "Wiadomości w tym pokoju nie są szyfrowane end-to-end.";
"room_member_power_level_admin_in" = "Admin w %@";
"room_member_power_level_moderator_in" = "Moderator w %@";
"room_member_power_level_custom_in" = "Inny (%@) w %@";
"room_member_power_level_short_admin" = "Administrator";
"room_member_power_level_short_moderator" = "Moderator";
"room_member_power_level_short_custom" = "Inny";
"room_accessiblity_scroll_to_bottom" = "Przewiń do dołu";
"room_accessibility_search" = "Szukaj";
"room_accessibility_integrations" = "Integracje";
"room_accessibility_upload" = "Wgraj";
"room_accessibility_call" = "Zadzwoń";
"room_accessibility_hangup" = "Rozłącz się";
"media_type_accessibility_image" = "Obraz";
"media_type_accessibility_audio" = "Dźwięk";
"media_type_accessibility_video" = "Film";
"media_type_accessibility_location" = "Lokalizacja";
"media_type_accessibility_file" = "Plik";
"media_type_accessibility_sticker" = "Naklejka";
"external_link_confirmation_title" = "Sprawdź ten link";
"external_link_confirmation_message" = "Link %@ przeniesie Cię na inną stronę: %@\n\nJesteś pewny, że chcesz kontynuować?";
"settings_discovery_settings" = "DISCOVERY";
"settings_identity_server_settings" = "Serwer tożsamości";
"settings_integrations" = "INTEGRACJE";
"settings_three_pids_management_information_part2" = "Discovery";
"settings_three_pids_management_information_part3" = ".";
"settings_security" = "BEZPIECZEŃSTWO";
"settings_calls_stun_server_fallback_button" = "Zezwalaj na rezerwowy serwer połączeń";
"settings_integrations_allow_button" = "Zarządzaj integracjami";
"settings_add_3pid_password_title_email" = "Dodaj adres email";
"settings_add_3pid_password_title_msidsn" = "Dodaj numer telefonu";
"settings_add_3pid_password_message" = "Aby kontynuować, podaj swoje hasło";
"settings_add_3pid_invalid_password_message" = "Niepoprawne hasło";
"settings_discovery_three_pids_management_information_part2" = "Ustawienia użytkownika";
"settings_discovery_three_pids_management_information_part3" = ".";
"settings_discovery_error_message" = "Wystąpił błąd. Spróbuj ponownie.";
"settings_discovery_three_pid_details_title_email" = "Zarządzaj email";
"settings_discovery_three_pid_details_title_phone_number" = "Zarządzaj numerem telefonu";
"settings_discovery_three_pid_details_share_action" = "Udostępnij";
"settings_discovery_three_pid_details_revoke_action" = "Unieważnij";
"settings_discovery_three_pid_details_cancel_email_validation_action" = "Przerwij walidacje adresu email";
"settings_discovery_three_pid_details_enter_sms_code_action" = "Podaj kod aktywacyjny SMS";
"settings_identity_server_no_is" = "Nieskonfigurowany serwer tożsamości";
// Security settings
"security_settings_title" = "Bezpieczeństwo";
"security_settings_crypto_sessions" = "MOJE SESJE";
"security_settings_crypto_sessions_loading" = "Ładowanie sesji…";
"security_settings_secure_backup" = "BEZPIECZNY BACKUP";
"security_settings_secure_backup_setup" = "Ustaw";
"security_settings_secure_backup_synchronise" = "Synchronizuj";
"security_settings_secure_backup_delete" = "Usuń";
"security_settings_backup" = "BACKUP WIADOMOŚCI";
"security_settings_crosssigning" = "PODPISYWANIE KRZYŻOWE";
"security_settings_crosssigning_info_not_bootstrapped" = "Podpisywanie krzyżowe nie jest ustawione.";
"room_info_list_section_other" = "Inne";

View file

@ -67,7 +67,7 @@
"auth_missing_phone" = "Falta o número de telefone";
"auth_missing_email_or_phone" = "Falta o endereço de e-mail ou o número de telefone";
"auth_email_in_use" = "Este endereço de e-mail já está sendo usado por outra pessoa";
"auth_phone_in_use" = "Este número de telefone já está sendo usado por outra pessoa";
"auth_phone_in_use" = "Este número de telefone já está em uso";
"auth_untrusted_id_server" = "Este servidor de identidades não é confiável";
"auth_password_dont_match" = "As senhas não correspondem";
"auth_username_in_use" = "Nome de usuário indisponível";
@ -1088,7 +1088,7 @@
"key_verification_scan_confirmation_scanned_device_information" = "O outro aparelho está mostrando o mesmo escudo?";
"user_verification_start_verify_action" = "Iniciar a confirmação";
"user_verification_start_information_part1" = "Para segurança extra, confirme· ";
"user_verification_start_information_part2" = " ·comparando um código único em ambos os aparelhos.";
"user_verification_start_information_part2" = " comparando um código único em ambos os aparelhos.";
"user_verification_start_additional_information" = "Para sua segurança, faça isso pessoalmente ou use outra forma de comunicação.";
"user_verification_sessions_list_user_trust_level_trusted_title" = "Confiável";
"user_verification_sessions_list_user_trust_level_unknown_title" = "Desconhecido";

View file

@ -285,7 +285,7 @@
"settings_crypto_export" = "Экспорт ключей";
"settings_crypto_blacklist_unverified_devices" = "Шифрование только для проверенных сеансов";
"room_details_people" = "Участники";
"room_details_files" = "Файлы";
"room_details_files" = "Вложения";
"room_details_settings" = "Настройки";
"room_details_photo" = "Изображение комнаты";
"room_details_room_name" = "Название комнаты";
@ -951,7 +951,7 @@
"security_settings_blacklist_unverified_devices_description" = "Проверьте все сеансы пользователей, чтобы пометить их как доверенные и отправить им сообщения.";
"security_settings_complete_security_alert_title" = "Завершите настройку безопасности";
"security_settings_complete_security_alert_message" = "Сначала вы должны завершить настройку безопасности текущего сеанса.";
"security_settings_coming_soon" = "Извините. Это действие пока недоступно в Element iOS. Пожалуйста, используйте другой клиент Matrix для его настройки. Элемент iOS будет его использовать.";
"security_settings_coming_soon" = "Извините. Это действие пока недоступно в Element iOS. Пожалуйста, используйте другой клиент Matrix для его настройки. Element iOS будет его использовать.";
"security_settings_user_password_description" = "Подтвердите свою личность, введя пароль учетной записи";
// Manage session
"manage_session_title" = "Управление сеансами";
@ -1156,7 +1156,7 @@
"major_update_information" = "Мы рады сообщить, что сменили имя! Ваше приложение обновлено, и вы вошли в свою учетную запись.";
"major_update_learn_more_action" = "Узнать больше";
"major_update_done_action" = "Понял";
"pin_protection_choose_pin" = "Выберите PIN-код для обеспечения безопасности";
"pin_protection_choose_pin" = "Создайте PIN-код для безопасности";
"pin_protection_confirm_pin" = "Подтвердите свой PIN-код";
"pin_protection_confirm_pin_to_disable" = "Подтвердите PIN-код, чтобы отключить PIN-код";
"pin_protection_enter_pin" = "Введите ваш PIN-код";
@ -1186,3 +1186,48 @@
"biometrics_cant_unlocked_alert_message_login" = "Войти снова";
"biometrics_cant_unlocked_alert_message_retry" = "Попробовать снова";
"device_verification_self_verify_wait_recover_secrets_checking_availability" = "Поиск других возможностей проверки…";
"joined" = "Присоединился";
"switch" = "Сменить";
"more" = "Ещё";
"pin_protection_choose_pin_welcome_after_login" = "С возвращением.";
"pin_protection_choose_pin_welcome_after_register" = "Добро пожаловать.";
"pin_protection_not_allowed_pin" = "По соображениям безопасности этот PIN-код недоступен. Пожалуйста, попробуйте другой PIN-код";
"pin_protection_explanatory" = "PIN-коды помогают защитить ваш профиль, сообщения и контакты, поэтому только вы можете получить к ним доступ.";
"searchable_directory_create_new_room" = "Создать новую комнату";
"searchable_directory_x_network" = "%@ Сеть";
"searchable_directory_search_placeholder" = "Имя или ID";
"create_room_title" = "Новая комната";
"create_room_section_header_name" = "Имя комнаты";
"create_room_placeholder_name" = "Имя";
"create_room_section_header_topic" = "Тема комнаты (опционально)";
"create_room_placeholder_topic" = "Тема";
"create_room_section_header_encryption" = "Шифрование комнаты";
"create_room_enable_encryption" = "Включено шифрование";
"create_room_section_footer_encryption" = "После этого шифрование отключить нельзя.";
"create_room_section_header_type" = "Тип комнаты";
"create_room_type_private" = "Приватная комната";
"create_room_type_public" = "Публичная комната";
"create_room_section_footer_type" = "Люди присоединяются к приватной комнате только по приглашению в комнату.";
"create_room_show_in_directory" = "Показать комнату в списке";
"create_room_section_header_address" = "Адрес комнаты";
"create_room_placeholder_address" = "#testroom:matrix.org";
"room_info_list_room_encrypted" = "Сообщения в этой комнате зашифрованы сквозным шифрованием";
"room_info_list_one_member" = "1 пользователь";
"room_info_list_several_members" = "%@ участников";
"room_info_list_section_other" = "Другое";
"room_participants_leave_prompt_title_for_dm" = "Покинуть";
"room_participants_leave_prompt_msg_for_dm" = "Вы уверены, что хотите покинуть?";
"room_participants_filter_room_members_for_dm" = "Фильтр участников";
"room_participants_security_information_room_not_encrypted_for_dm" = "Сообщения здесь не зашифрованы.";
"room_participants_security_information_room_encrypted_for_dm" = "Сообщения здесь зашифрованы.\n\nВаши сообщения защищены замками, и только у вас и получателя есть уникальные ключи для их разблокировки.";
"room_details_title_for_dm" = "Подробности";
"room_details_photo_for_dm" = "Фото";
"room_details_room_name_for_dm" = "Имя";
"room_details_access_section_for_dm" = "Кто имеет к этому доступ?";
"room_details_access_section_anyone_apart_from_guest_for_dm" = "Все у кого есть ссылка, кроме гостей";
"room_details_access_section_anyone_for_dm" = "Все у кого есть ссылка, включая гостей";
"room_details_access_section_directory_toggle_for_dm" = "Отображать в каталоге комнат";
"room_details_no_local_addresses_for_dm" = "Ещё нет локального адреса";
"room_details_advanced_room_id_for_dm" = "ID:";
"room_details_advanced_e2e_encryption_enabled_for_dm" = "Шифрование включено";
"room_details_advanced_e2e_encryption_disabled_for_dm" = "Шифрование не включено.";

View file

@ -271,7 +271,7 @@
// Room Details
"room_details_title" = "Hollësi Dhome";
"room_details_people" = "Anëtarë";
"room_details_files" = "Kartela";
"room_details_files" = "Ngarkime";
"room_details_settings" = "Rregullime";
"room_details_photo" = "Foto Dhome";
"room_details_room_name" = "Emër Dhome";
@ -1160,7 +1160,7 @@
"major_update_information" = "Jemi të ngazëllyer tju njoftojmë se ndryshuam emër! Aplikacioni juaj është i përditësuar dhe jeni i futur te llogaria juaj.";
"major_update_learn_more_action" = "Mësoni më tepër";
"major_update_done_action" = "E mora vesh";
"pin_protection_choose_pin" = "Zgjidhni një PIN për siguri";
"pin_protection_choose_pin" = "Krijoni një PIN për siguri";
"pin_protection_confirm_pin" = "Ripohoni PIN-in tuaj";
"pin_protection_confirm_pin_to_disable" = "Ripohoni PIN-in që të çaktivizohet PIN-i";
"pin_protection_enter_pin" = "Jepni PIN-in tuaj";
@ -1189,3 +1189,30 @@
"biometrics_cant_unlocked_alert_message_login" = "Ribëni hyrjen";
"biometrics_cant_unlocked_alert_message_retry" = "Riprovoni";
"device_verification_self_verify_wait_recover_secrets_checking_availability" = "Po kontrollohet për aftësi të tjera verifikimi …";
"more" = "Më tepër";
"pin_protection_choose_pin_welcome_after_login" = "Mirë se u kthyet.";
"pin_protection_choose_pin_welcome_after_register" = "Mirë se vini.";
"pin_protection_not_allowed_pin" = "Për arsye sigurie, ky PIN sështë i passhëm. Ju lutemi, provoni një PIN tjetër";
"pin_protection_explanatory" = "PIN-et ndihmojnë për të mbajtur të siguruar profilin, mesazhet dhe kontaktet tuaja, që kështu të mund ti përdorni.";
"searchable_directory_create_new_room" = "Krijoni një dhomë të re";
"searchable_directory_x_network" = "Rrjet %@";
"searchable_directory_search_placeholder" = "Emër ose ID";
"create_room_title" = "Dhomë e Re";
"create_room_section_header_name" = "Emër dhome";
"create_room_placeholder_name" = "Emër";
"create_room_section_header_topic" = "Temë dhome (në daçi)";
"create_room_placeholder_topic" = "Temë";
"create_room_section_header_encryption" = "Fshehtëzim dhome";
"create_room_enable_encryption" = "Aktivizoni Fshehtëzim";
"create_room_section_footer_encryption" = "Fshehtëzimi smund të çaktivizohet më pas.";
"create_room_section_header_type" = "Lloj dhome";
"create_room_type_private" = "Dhomë Private";
"create_room_type_public" = "Dhomë Publike";
"create_room_section_footer_type" = "Njerëzit marrin pjesë në një dhomë vetëm me ftesën për te dhoma.";
"create_room_show_in_directory" = "Shfaqe dhomën te lista";
"create_room_section_header_address" = "Adresë dhome";
"create_room_placeholder_address" = "#provëdhome:matrix.org";
"room_info_list_room_encrypted" = "Mesazhet në këtë dhomë janë të fshehtëzuar skaj më skaj";
"room_info_list_one_member" = "1 anëtar";
"room_info_list_several_members" = "%@ anëtarë";
"room_info_list_section_other" = "Tjetër";

View file

@ -90,16 +90,16 @@
"room_creation_appearance" = "Utseende";
"room_creation_appearance_name" = "Namn";
"room_creation_appearance_picture" = "Chattbild (valfritt)";
"room_creation_privacy" = "Integritet";
"room_creation_privacy" = "Privatliv";
"room_creation_private_room" = "Den här chatten är privat";
"room_creation_public_room" = "Den här chatten är publik";
"room_creation_make_public" = "Gör publik";
"room_creation_make_public_prompt_title" = "Gör den här chatten publik?";
"room_creation_make_public_prompt_msg" = "Är du säker på att du vill göra den här chatten publik? Vem som helst kan läsa dina meddelanden och gå med i chatten.";
"room_creation_public_room" = "Den här chatten är offentlig";
"room_creation_make_public" = "Gör offentlig";
"room_creation_make_public_prompt_title" = "Gör den här chatten offentlig?";
"room_creation_make_public_prompt_msg" = "Är du säker på att du vill göra den här chatten offentlig? Vem som helst kan läsa dina meddelanden och gå med i chatten.";
"room_creation_keep_private" = "Behåll privat";
"room_creation_make_private" = "Gör privat";
"room_creation_wait_for_creation" = "Ett rum håller redan på att skapas. Vänligen vänta.";
"room_creation_invite_another_user" = "Sök / bjud in efter användar-ID, namn eller e-post";
"room_creation_invite_another_user" = "Sök / bjud in efter användar-ID, namn eller e-postadress";
"room_recents_directory_section_network" = "Nätverk";
"room_recents_favourites_section" = "FAVORITER";
"room_recents_people_section" = "PERSONER";
@ -117,7 +117,7 @@
"people_conversation_section" = "KONVERSATIONER";
"people_no_conversation" = "Inga konversationer";
// Rooms tab
"room_directory_no_public_room" = "Inga publika rum tillgängliga";
"room_directory_no_public_room" = "Inga offentliga rum tillgängliga";
// Groups tab
"group_invite_section" = "INBJUDNINGAR";
// Search
@ -126,7 +126,7 @@
"search_people" = "Personer";
"search_files" = "Filer";
"search_default_placeholder" = "Sök";
"search_people_placeholder" = "Sök efter användar-ID, namn eller e-post";
"search_people_placeholder" = "Sök efter användar-ID, namn eller e-postadress";
"search_no_result" = "Inga resultat";
"search_in_progress" = "Söker…";
"directory_cell_description" = "%tu rum";
@ -149,7 +149,7 @@
"room_participants_remove_third_party_invite_prompt_msg" = "Är du säker på att du vill återkalla den här inbjudan?";
"room_participants_invite_prompt_title" = "Bekräftelse";
"room_participants_invite_prompt_msg" = "Är du säker på att du vill bjuda in %s till den här chatten?";
"room_participants_invite_another_user" = "Sök / bjud in efter användar-ID, namn eller e-post";
"room_participants_invite_another_user" = "Sök / bjud in efter användar-ID, namn eller e-postadress";
"room_participants_invite_malformed_id" = "Felformaterat ID. Ska vara en e-postadress eller ett Matrix-ID som '@lokaldel:domän'";
"room_participants_online" = "Online";
"room_participants_offline" = "Offline";
@ -163,7 +163,7 @@
"room_participants_action_remove" = "Ta bort från det här rummet";
"room_participants_action_ban" = "Banna från det här rummet";
"room_participants_action_unban" = "Avbanna";
"room_participants_action_ignore" = "Göm alla meddelanden från den här användaren";
"room_participants_action_ignore" = "Dölj alla meddelanden från den här användaren";
"room_participants_action_unignore" = "Visa alla meddelanden från den här användaren";
"room_participants_action_set_default_power_level" = "Återställ till vanlig användare";
"room_participants_action_set_moderator" = "Gör till moderator";
@ -173,11 +173,11 @@
"room_participants_action_start_video_call" = "Starta videosamtal";
"room_participants_action_security_status_verified" = "Verifierad";
"room_participants_action_security_status_verify" = "Verifiera";
"room_participants_action_security_status_complete_security" = "Fullständig säkerhet";
"room_participants_action_security_status_complete_security" = "Fullborda säkerhet";
"room_participants_action_security_status_warning" = "Varning";
"room_participants_action_security_status_loading" = "Laddar…";
"room_participants_security_loading" = "Laddar…";
"room_participants_security_information_room_not_encrypted" = "Meddelanden i det här rummet är inte end-to-end-krypterade.";
"room_participants_security_information_room_not_encrypted" = "Meddelanden i det här rummet är inte totalsträckskrypterade.";
"room_member_power_level_admin_in" = "Admin i %@";
"room_member_power_level_moderator_in" = "Moderator i %@";
"room_member_power_level_custom_in" = "Anpassad (%@) i %@";
@ -185,7 +185,7 @@
"room_member_power_level_short_moderator" = "Mod";
"room_member_power_level_short_custom" = "Anpassad";
// Chat
"room_jump_to_first_unread" = "Hoppa till första olästa meddelande";
"room_jump_to_first_unread" = "Hoppa till första olästa meddelandet";
"room_new_message_notification" = "%d nytt meddelande";
"room_new_messages_notification" = "%u nya meddelanden";
"room_one_user_is_typing" = "%@ skriver…";
@ -201,7 +201,7 @@
"room_offline_notification" = "Anslutning till servern har brutits.";
"room_ongoing_conference_call_close" = "Stäng";
"room_prompt_cancel" = "avbryt alla";
"room_delete_unsent_messages" = "Radera ej skickade meddelanden";
"room_delete_unsent_messages" = "Radera oskickade meddelanden";
"room_event_action_copy" = "Kopiera";
"room_event_action_quote" = "Citera";
"room_event_action_redact" = "Ta bort";
@ -214,7 +214,7 @@
"room_event_action_report_prompt_reason" = "Anledning för att rapportera det här innehållet";
"room_event_action_kick_prompt_reason" = "Skäl till att kicka den här användaren";
"room_event_action_ban_prompt_reason" = "Skäl till att banna den här användaren";
"room_event_action_report_prompt_ignore_user" = "Vill du gömma alla meddelanden från den här användaren?";
"room_event_action_report_prompt_ignore_user" = "Vill du dölja alla meddelanden från den här användaren?";
"room_event_action_save" = "Spara";
"room_event_action_resend" = "Skicka igen";
"room_event_action_delete" = "Radera";
@ -222,7 +222,7 @@
"room_event_action_view_encryption" = "Krypteringsinformation";
"room_event_action_reply" = "Svara";
"room_event_action_edit" = "Redigera";
"room_event_action_reaction_show_all" = "Visa alla";
"room_event_action_reaction_show_all" = "Visa allt";
"room_event_action_reaction_show_less" = "Visa mindre";
"room_event_action_reaction_history" = "Reaktionshistorik";
"room_action_camera" = "Ta en bild eller video";
@ -230,11 +230,11 @@
"room_action_send_sticker" = "Skicka dekal";
"room_action_send_file" = "Skicka fil";
"room_action_reply" = "Svara";
"room_replacement_information" = "Det här rumet har ersatts och är inte längre aktivt.";
"room_replacement_information" = "Det här rummet har ersatts och är inte längre aktivt.";
"room_replacement_link" = "Konversationen fortsätter här.";
"room_predecessor_information" = "Det här rumet är en fortsättning på en annan konversation.";
"room_predecessor_link" = "Tryck här för att se äldre meddelanden.";
"room_message_edits_history_title" = "Meddelandedigeringar";
"room_message_edits_history_title" = "Meddelanderedigeringar";
"room_accessibility_search" = "Sök";
"room_accessibility_integrations" = "Integrationer";
"room_accessibility_upload" = "Ladda upp";
@ -246,7 +246,7 @@
"external_link_confirmation_title" = "Dubbelkolla den här länken";
"external_link_confirmation_message" = "Länken %@ tar dig till en annan webbplats: %@\n\nÄr du säker på att du vill fortsätta?";
// Unknown devices
"unknown_devices_alert_title" = "Rum innehåller okända sessioner";
"unknown_devices_alert_title" = "Rummet innehåller okända sessioner";
"unknown_devices_send_anyway" = "Skicka ändå";
"unknown_devices_call_anyway" = "Ring ändå";
"unknown_devices_answer_anyway" = "Svara ändå";
@ -270,9 +270,9 @@
"settings_config_identity_server" = "Identitetsserver är %@";
"settings_config_user_id" = "Inloggad som %@";
"settings_user_settings" = "ANVÄNDARINSTÄLLNINGAR";
"settings_notifications_settings" = "NOTISINSTÄLLNINGAR";
"settings_notifications_settings" = "AVISERINGSINSTÄLLNINGAR";
"settings_calls_settings" = "SAMTAL";
"settings_discovery_settings" = "UPPTÄCK";
"settings_discovery_settings" = "UPPTÄCKT";
"settings_identity_server_settings" = "IDENTITETSSERVER";
"settings_integrations" = "INTEGRATIONER";
"settings_user_interface" = "ANVÄNDARGRÄNSSNITT";
@ -280,14 +280,14 @@
"settings_contacts" = "LOKALA KONTAKTER";
"settings_advanced" = "AVANCERAT";
"settings_other" = "ANNAT";
"settings_labs" = "LABB";
"settings_labs" = "EXPERIMENT";
"settings_devices" = "SESSIONER";
"settings_cryptography" = "KRYPTOGRAFI";
"settings_key_backup" = "NYCKELBACKUP";
"settings_key_backup" = "NYCKELSÄKERHETSKOPIERING";
"settings_deactivate_account" = "INAKTIVERA KONTO";
"settings_sign_out" = "Logga ut";
"settings_sign_out_confirmation" = "Är du säker?";
"settings_sign_out_e2e_warn" = "Du kommer att förlora dina end-to-end-krypteringsnycklar. Detta betyder att du inte längre kommer att kunna läsa gamla meddelanden i krypterade rum på den här enheten.";
"settings_sign_out_e2e_warn" = "Du kommer att förlora dina nycklar för totalsträckskryptering. Detta betyder att du inte längre kommer att kunna läsa gamla meddelanden i krypterade rum på den här enheten.";
"settings_profile_picture" = "Profilbild";
"settings_display_name" = "Visningsnamn";
"settings_first_name" = "Förnamn";
@ -302,15 +302,15 @@
"settings_add_phone_number" = "Lägg till telefonnummer";
"settings_change_password" = "Ändra lösenord";
"settings_night_mode" = "Nattläge";
"settings_fail_to_update_profile" = "Kunde inte uppdatera profil";
"settings_fail_to_update_profile" = "Misslyckades att uppdatera profil";
"settings_three_pids_management_information_part1" = "Hantera vilka e-postadresser eller telefonnummer som du kan använda för att logga in eller återfå ditt konto här. Kontrollera vilka som kan hitta dig i ";
"settings_three_pids_management_information_part2" = "Upptäck";
"settings_three_pids_management_information_part2" = "Upptäckt";
"settings_security" = "SÄKERHET";
"settings_enable_push_notif" = "Notiser på den här enheten";
"settings_enable_push_notif" = "Aviseringar på den här enheten";
"settings_show_decrypted_content" = "Visa avkrypterat innehåll";
"settings_pin_rooms_with_missed_notif" = "Fäst rum med missade notiser";
"settings_pin_rooms_with_missed_notif" = "Fäst rum med missade aviseringar";
"settings_pin_rooms_with_unread" = "Fäst rum med olästa meddelanden";
"settings_on_denied_notification" = "Notiser har nekats för %@, vänligen tillåt dem i dina enhetsinställningar";
"settings_on_denied_notification" = "Aviseringar har nekats för %@, vänligen tillåt dem i dina enhetsinställningar";
"settings_enable_callkit" = "Integrerade samtal";
"settings_integrations_allow_button" = "Hantera integrationer";
"settings_ui_language" = "Språk";
@ -322,25 +322,25 @@
"settings_ui_theme_picker_title" = "Välj ett tema";
"settings_unignore_user" = "Visa alla meddelanden från %@?";
"settings_contacts_discover_matrix_users" = "Använd e-postadresser och telefonnummer för att upptäcka användare";
"settings_labs_e2e_encryption" = "End-to-end-kryptering";
"settings_labs_e2e_encryption" = "Totalsträckskryptering";
"settings_labs_e2e_encryption_prompt_message" = "För att slutföra inställningen av kryptering måste du logga in igen.";
"settings_labs_create_conference_with_jitsi" = "Skapa gruppsamtal med jitsi";
"settings_labs_message_reaction" = "Reagera på meddelanden med emoji";
"settings_version" = "Version %@";
"settings_copyright" = "Copyright";
"settings_term_conditions" = "Villkor";
"settings_copyright" = "Upphovsrätt";
"settings_term_conditions" = "Användarvillkor";
"settings_privacy_policy" = "Integritetspolicy";
"settings_send_crash_report" = "Skicka anonyma krasch- och användningsdata";
"settings_enable_rageshake" = "Skaka ilsket för att rapportera bugg";
"settings_enable_rageshake" = "Raseriskaka för att rapportera bugg";
"settings_old_password" = "gammalt lösenord";
"settings_new_password" = "nytt lösenord";
"settings_confirm_password" = "bekräfta lösenord";
"settings_fail_to_update_password" = "Kunde inte uppdatera lösenord";
"settings_fail_to_update_password" = "Misslyckades att uppdatera lösenord";
"settings_password_updated" = "Ditt lösenord har uppdaterats";
"settings_add_3pid_password_title_email" = "Lägg till e-postadress";
"settings_add_3pid_password_title_msidsn" = "Lägg till telefonnummer";
"settings_add_3pid_password_message" = "För att fortsätta, ange ditt lösenord";
"settings_add_3pid_invalid_password_message" = "Felaktigt lösenord";
"settings_add_3pid_invalid_password_message" = "Ogiltigt lösenord";
"settings_crypto_export" = "Exportera nycklar";
"settings_crypto_blacklist_unverified_devices" = "Kryptera endast till verifierade sessioner";
"settings_deactivate_my_account" = "Inaktivera mitt konto";
@ -359,14 +359,14 @@
"settings_key_backup_button_restore" = "Återskapa från säkerhetskopia";
"settings_key_backup_button_delete" = "Radera säkerhetskopia";
"settings_key_backup_delete_confirmation_prompt_title" = "Radera säkerhetskopia";
"settings_key_backup_delete_confirmation_prompt_msg" = "Är du säker? Du kommer att förlora dina krypterade meddelanden om dina nycklar inte säkerhetskopieras ordentligt.";
"settings_devices_description" = "En sessions publika namn är synligt för personer du kommunicerar med";
"settings_key_backup_delete_confirmation_prompt_msg" = "Är du säker? Du kommer att förlora dina krypterade meddelanden om dina nycklar inte har säkerhetskopierats ordentligt.";
"settings_devices_description" = "En sessions offentliga namn är synligt för personer du kommunicerar med";
"settings_discovery_three_pids_management_information_part2" = "Användarinställningar";
"settings_discovery_error_message" = "Ett fel uppstod. Försök igen.";
"settings_discovery_three_pid_details_title_email" = "Hantera e-post";
"settings_discovery_three_pid_details_information_email" = "Hantera inställningar för den här e-postadressen, som andra kan använda för att upptäcka dig och för att bjuda in dig till rum. Lägg till eller ta bort e-postadresser under Konton.";
"settings_discovery_three_pid_details_information_email" = "Hantera inställningar för den här e-postadressen, vilken andra kan använda för att upptäcka dig och för att bjuda in dig till rum. Lägg till eller ta bort e-postadresser under Konton.";
"settings_discovery_three_pid_details_title_phone_number" = "Hantera telefonnummer";
"settings_discovery_three_pid_details_information_phone_number" = "Hantera inställningar för det här telefonnumret, som andra kan använda för att upptäcka dig och för att bjuda in dig till rum. Lägg till eller ta bort telefonummer under Konton.";
"settings_discovery_three_pid_details_information_phone_number" = "Hantera inställningar för det här telefonnumret, vilket andra kan använda för att upptäcka dig och för att bjuda in dig till rum. Lägg till eller ta bort telefonnummer under Konton.";
"settings_discovery_three_pid_details_share_action" = "Dela";
"settings_discovery_three_pid_details_revoke_action" = "Återkalla";
"settings_discovery_three_pid_details_cancel_email_validation_action" = "Avbryt e-postvalidering";
@ -381,8 +381,8 @@
"security_settings_cryptography" = "KRYPTOGRAFI";
"security_settings_export_keys_manually" = "Exportera nycklar manuellt";
"security_settings_advanced" = "AVANCERAT";
"security_settings_blacklist_unverified_devices" = "Skicka aldrig meddelanden till otillförlitliga sessioner";
"security_settings_blacklist_unverified_devices_description" = "Verifiera en användares alla sessioner för att markera den som tillförlitlig och skicka meddelanden till den.";
"security_settings_blacklist_unverified_devices" = "Skicka aldrig meddelanden till obetrodda sessioner";
"security_settings_blacklist_unverified_devices_description" = "Verifiera en användares alla sessioner för att markera den som betrodd och skicka meddelanden till den.";
"security_settings_user_password_description" = "Bekräfta din identitet genom att ange ditt kontolösenord";
// Manage session
"manage_session_title" = "Hantera session";
@ -425,7 +425,7 @@
"auth_softlogout_clear_data_message_2" = "Rensa datan om du inte längre kommer att använda den här enheten, eller vill logga in på ett annat konto.";
"auth_softlogout_clear_data_button" = "Rensa alla data";
"auth_softlogout_clear_data_sign_out_msg" = "Är du säker på att du vill rensa alla data som för närvarande lagras på den här enheten? Logga in igen för att tillgång till dina kontodata och meddelanden.";
"room_creation_error_invite_user_by_email_without_identity_server" = "Ingen identitetsserver är konfigurerad, så du kan inte lägga till en deltagare via e-post.";
"room_creation_error_invite_user_by_email_without_identity_server" = "Ingen identitetsserver är konfigurerad, så du kan inte lägga till en deltagare via e-postadress.";
"contacts_address_book_permission_required" = "Behörighet krävs för att få tillgång till dina lokala kontakter";
"contacts_address_book_permission_denied" = "Du gav inte Element åtkomst till dina lokala kontakter";
"room_participants_invite_malformed_id_title" = "Fel vid inbjudan";
@ -435,7 +435,7 @@
"room_participants_action_section_direct_chats" = "Direktchattar";
"room_participants_action_invite" = "Bjud in";
"room_participants_action_mention" = "Nämn";
"room_participants_security_information_room_encrypted" = "Meddelanden i det här rummet är end-to-end-kryptering.\n \nDina meddelanden är säkrade med lås och bara du och mottagaren har de unika nycklarna för att låsa upp dem.";
"room_participants_security_information_room_encrypted" = "Meddelanden i det här rummet är totalsträckskrypterade.\n\nDina meddelanden är säkrade med lås och bara du och mottagaren har de unika nycklarna för att låsa upp dem.";
"room_accessiblity_scroll_to_bottom" = "Scrolla till botten";
"room_do_not_have_permission_to_post" = "Du har inte behörighet att posta till det här rummet";
"room_unsent_messages_notification" = "Meddelanden skickades inte. %@ eller %@ nu?";
@ -446,14 +446,14 @@
"media_type_accessibility_image" = "Bild";
// Room Preview
"room_preview_invitation_format" = "Du har blivit inbjuden till det här rummet av %s";
"settings_global_settings_info" = "Globala notisinställningar är tillgängliga i webbklienten för %@";
"settings_global_settings_info" = "Globala aviseringsinställningar är tillgängliga i webbklienten för %@";
"settings_third_party_notices" = "Tredjepartslicenser";
"settings_crypto_device_name" = "Sessionsnamn: ";
"settings_crypto_device_id" = "\nSessions-ID: ";
"settings_key_backup_info" = "Krypterade meddelanden är säkrade med end-to-end-kryptering. Bara du och mottagaren/na har nycklarna för att läsa dessa meddelanden.";
"settings_key_backup_info_version" = "Version för nyckelbackup: %@";
"settings_key_backup_button_create" = "Börja använd nyckelbackup";
"settings_key_backup_button_connect" = "Anslut den här sessionen till nyckelbackup";
"settings_key_backup_info" = "Krypterade meddelanden är säkrade med totalsträckskryptering. Bara du och mottagaren/na har nycklarna för att läsa dessa meddelanden.";
"settings_key_backup_info_version" = "Version för nyckelsäkerhetskopia: %@";
"settings_key_backup_button_create" = "Börja använda nyckelsäkerhetskopiering";
"settings_key_backup_button_connect" = "Anslut den här sessionen till nyckelsäkerhetskopia";
"security_settings_crosssigning" = "KORSSIGNERING";
"security_settings_crosssigning_info_not_bootstrapped" = "Korssignering har ännu inte ställts in.";
"security_settings_crosssigning_info_ok" = "Korssignering är aktiverat.";
@ -494,12 +494,12 @@
"room_details_advanced_e2e_encryption_enabled" = "Kryptering är aktiverat i det här rummet";
"room_details_advanced_e2e_encryption_disabled" = "Kryptering är inte aktiverat i det här rummet.";
"room_details_advanced_e2e_encryption_blacklist_unverified_devices" = "Kryptera endast till verifierade sessioner";
"room_details_fail_to_update_topic" = "Kunde inte uppdatera ämnet";
"room_details_fail_to_update_history_visibility" = "Kunde inte uppdatera synlighet för historiken";
"room_details_fail_to_add_room_aliases" = "Kunde inte lägga till de nya rumsadresserna";
"room_details_fail_to_remove_room_aliases" = "Kunde inte ta bort rumsadresserna";
"room_details_fail_to_update_room_canonical_alias" = "Kunde inte uppdatera huvudadressen";
"room_details_fail_to_enable_encryption" = "Kunde inte aktivera kryptering i det här rummet";
"room_details_fail_to_update_topic" = "Misslyckades att uppdatera ämnet";
"room_details_fail_to_update_history_visibility" = "Misslyckades att uppdatera synlighet för historiken";
"room_details_fail_to_add_room_aliases" = "Misslyckades att lägga till de nya rumsadresserna";
"room_details_fail_to_remove_room_aliases" = "Misslyckades att ta bort rumsadresserna";
"room_details_fail_to_update_room_canonical_alias" = "Misslyckades att uppdatera huvudadressen";
"room_details_fail_to_enable_encryption" = "Misslyckades att aktivera kryptering i det här rummet";
"room_details_save_changes_prompt" = "Vill du spara ändringar?";
"room_details_set_main_address" = "Ställ in som huvudadress";
"room_details_copy_room_id" = "Kopiera rums-ID";
@ -520,12 +520,12 @@
"group_participants_remove_prompt_msg" = "Är du säker på att du vill ta bort %s från den här gruppen?";
"group_participants_invite_prompt_title" = "Bekräftelse";
"group_participants_invite_prompt_msg" = "Är du säker på att du vill bjuda in %s till den här gruppen?";
"group_participants_filter_members" = "Filtrera community-medlemmar";
"group_participants_filter_members" = "Filtrera gemenskapsmedlemmar";
"group_participants_invite_another_user" = "Sök / bjud in efter användar-ID eller namn";
"group_participants_invite_malformed_id_title" = "Fel vid inbjudan";
"group_participants_invite_malformed_id" = "Felformaterat ID. Ska vara ett Matrix-ID som '@lokaldel:domän'";
// Group rooms
"group_rooms_filter_rooms" = "Filtrera community-rum";
"group_rooms_filter_rooms" = "Filtrera gemenskapsrum";
// Media picker
"media_picker_title" = "Mediabibliotek";
"media_picker_library" = "Bibliotek";
@ -534,17 +534,17 @@
"directory_server_placeholder" = "matrix.org";
// Events formatter
"event_formatter_member_updates" = "%tu förändringar av medlemskap";
"event_formatter_widget_added" = "%@ widget tillagd av %@";
"event_formatter_widget_removed" = "%@ widget borttagen av %@";
"event_formatter_widget_added" = "%@-widget tillagd av %@";
"event_formatter_widget_removed" = "%@-widget borttagen av %@";
// Events formatter with you
"event_formatter_widget_added_by_you" = "Du la till widgeten: %@";
"event_formatter_widget_removed_by_you" = "Du la till widgeten: %@";
"event_formatter_widget_added_by_you" = "Du lade till widgeten: %@";
"event_formatter_widget_removed_by_you" = "Du lade till widgeten: %@";
// Others
"or" = "eller";
"you" = "Du";
"today" = "Idag";
"yesterday" = "Igår";
"network_offline_prompt" = "Internetanslutningen verkar vara offline.";
"network_offline_prompt" = "Internetuppkopplingen verkar vara offline.";
"homeserver_connection_lost" = "Kunde inte ansluta till identitetsservern.";
"rage_shake_prompt" = "Du verkar skaka din telefon i frustration. Vill du skicka en buggrapport?";
"do_not_ask_again" = "Fråga inte igen";
@ -556,7 +556,7 @@
// No VoIP support
"no_voip_title" = "Inkommande samtal";
// Key backup wrong version
"e2e_key_backup_wrong_version_title" = "Ny nyckelbackup";
"e2e_key_backup_wrong_version_title" = "Ny nyckelsäkerhetskopia";
"e2e_key_backup_wrong_version_button_settings" = "Inställningar";
"e2e_key_backup_wrong_version_button_wasme" = "Det var jag";
// Bug report
@ -597,13 +597,13 @@
"contacts_user_directory_section" = "ANVÄNDARKATALOG";
"contacts_user_directory_offline_section" = "ANVÄNDARKATALOG (offline)";
"room_participants_filter_room_members" = "Filtrera rumsmedlemmar";
"room_ongoing_conference_call" = "Pågående gruppsamtal. Gå med som %@ or %@.";
"room_ongoing_conference_call_with_close" = "Pågående gruppsamtal. Gå med %@ eller %@. %@ det.";
"room_event_action_cancel_send" = "Avbryt skicka";
"room_event_failed_to_send" = "Det gick inte att skicka";
"room_resource_limit_exceeded_message_contact_2_link" = "kontakta din administratör för tjänsten";
"room_ongoing_conference_call" = "Pågående gruppsamtal. Gå med som %@ eller %@.";
"room_ongoing_conference_call_with_close" = "Pågående gruppsamtal. Gå med som %@ eller %@. %@ det.";
"room_event_action_cancel_send" = "Avbryt sändning";
"room_event_failed_to_send" = "Misslyckades att skicka";
"room_resource_limit_exceeded_message_contact_2_link" = "kontakta din tjänsts administratör";
"unknown_devices_alert" = "Det här rummet innehåller okända sessioner som inte har verifierats.\nDetta betyder att det inte finns någon garanti att sessionerna tillhör användarna de påstår sig göra.\nVi rekommenderar att du går igenom verifieringsprocessen för varje session innan du fortsätter, men du kan skicka meddelandet utan att verifiera om du föredrar.";
"room_preview_subtitle" = "Det här är en förhandsvisning av det här rummet. Rumsinteraktioner har inaktiverats.";
"room_preview_subtitle" = "Det här är en förhandsgranskning av det här rummet. Rumsinteraktioner har inaktiverats.";
"room_preview_unlinked_email_warning" = "Den här inbjudan skickades till %@, vilket inte är associerat med det här kontot. Du kanske vill logga in på ett annat konto, eller lägga till den här e-postadressen till ditt konto.";
"room_preview_try_join_an_unknown_room" = "Du försöker komma åt %@. Skulle du vilja gå med för att delta i diskussionen?";
"settings_callkit_info" = "Ta emot inkommande samtal på din låsskärm. Se dina Element-samtal i systemets samtalshistorik. Om iCloud är aktiverat kommer denna samtalshistorik att delas med Apple.";
@ -612,13 +612,13 @@
"settings_ui_theme_picker_message" = "\"Auto\" använder dina enhetsinställningar för \"Invertera färger\"";
"settings_olm_version" = "Olm-version %@";
"settings_crypto_device_key" = "\nSessionsnyckel:\n";
"settings_key_backup_info_signout_warning" = "Anslut den här sessionen till nyckelbackup innan du loggar ut för att undvika förlust av någon nyckel som endast finns på den här enheten.";
"settings_key_backup_info_signout_warning" = "Anslut den här sessionen till nyckelsäkerhetskopiering innan du loggar ut för att undvika förlust av någon nyckel som endast finns på den här enheten.";
"settings_discovery_no_identity_server" = "Du använder för närvarande ingen identitetsserver. Lägg till en för att kunna upptäckas av befintliga kontakter du känner.";
"settings_discovery_terms_not_signed" = "Acceptera identitetsserverns (%@) användarvillkor för att låta dig själv vara upptäckbar med e-postadress eller telefonnummer.";
"security_settings_crypto_sessions_loading" = "Laddar sessioner…";
"security_settings_crosssigning_info_exists" = "Ditt konto har en identitet för korssignering, men den är ännu inte betrodd av den här sessionen. Slutför säkerheten för den här sessionen.";
"security_settings_crosssigning_info_trusted" = "Korssignering är aktiverat. Du kan lita på andra användare och dina andra sessioner baserat på korssignering, men du kan inte korssignera från den här sessionen eftersom den inte har privata nycklar för korssignering. Slutför säkerheten för den här sessionen.";
"security_settings_crosssigning_complete_security" = "Fullständig säkerhet";
"security_settings_crosssigning_complete_security" = "Fullborda säkerhet";
"security_settings_complete_security_alert_message" = "Du bör slutföra säkerheten på din nuvarande session först.";
"manage_session_not_trusted" = "Ej betrodd";
"identity_server_settings_alert_change" = "Koppla från identitetsservern %1$@ och anslut till %2$@ istället?";
@ -627,7 +627,7 @@
"identity_server_settings_alert_error_terms_not_accepted" = "Du måste acceptera villkoren hos %@ för att kunna ställa in den som identitetsserver.";
"identity_server_settings_alert_error_invalid_identity_server" = "%@ är inte en giltig identitetsserver.";
"service_terms_modal_message_identity_server" = "Acceptera villkoren hos identitetsservern (%@) för att upptäcka kontakter.";
"device_verification_self_verify_wait_additional_information" = "eller någon annan Matrix-klient som kan använda korssignering";
"device_verification_self_verify_wait_additional_information" = "eller någon annan Matrix-klient som stöder korssignering";
// Generic errors
"error_invite_3pid_with_no_identity_server" = "Lägg till en identitetsserver i dina inställningar för att bjuda in via e-post.";
"secrets_recovery_with_passphrase_information_default" = "Få tillgång till din säkra meddelandehistorik och din identitet för korssignering för att verifiera andra sessioner genom att ange din återställningslösenfras.";
@ -635,3 +635,508 @@
"auth_add_email_phone_message_2" = "Sätt en e-postadress för kontoåterställning. E-postadress och telefonnummer kan senare valfritt användas för att vara upptäckbar av folk som känner dig.";
"auth_add_email_and_phone_warning" = "Registrering med e-post och telefonnummer samtidigt stöds inte än, tills att API:t finns. Endast telefonnumret kommer att användas. Du kan lägga till din e-postadress till din profil i inställningarna.";
"auth_autodiscover_invalid_response" = "Ogiltigt upptäcktssvar från hemservern";
// Room recents
"room_recents_directory_section" = "RUMSKATALOG";
"room_recents_join_room_prompt" = "Skriv ett rums-ID eller rumsalias";
"group_section" = "GEMENSKAPER";
"directory_search_fail" = "Misslyckades att hämta data";
"room_participants_start_new_chat_error_using_user_email_without_identity_server" = "Ingen identitetsserver är konfigurerad så du kan inte starta en chatt med en kontakt med en e-postadress.";
"room_unsent_messages_unknown_devices_notification" = "Meddelandet skickades inte eftersom okända sessioner var närvarande. %@ eller %@ nu?";
"room_resend_unsent_messages" = "Skicka oskickade meddelanden igen";
"room_warning_about_encryption" = "Totalsträckskryptering är i beta, och kanske inte är pålitligt.\n\nDu bör inte ännu lita på att den säkrar data.\n\nEnheter kommer inte att kunna avkryptera historik från innan de gick med i rummet.\n\nKrypterade meddelanden kommer inte vara synliga på klienter som inte ännu stöder kryptering.";
"room_resource_limit_exceeded_message_contact_1" = " Vänligen ";
"room_resource_limit_exceeded_message_contact_3" = " för att fortsätta använda tjänsten.";
"room_resource_usage_limit_reached_message_1_default" = "Den här hemserver har överskridit en av sina resursgränser så ";
"room_resource_usage_limit_reached_message_1_monthly_active_user" = "Den här hemservern har överskridit sin månatliga aktivitetsgräns för användare så ";
"room_resource_usage_limit_reached_message_2" = "vissa användare kommer inte kunna logga in.";
"room_resource_usage_limit_reached_message_contact_3" = " för att öka den här gränsen.";
"settings_config_no_build_info" = "Ingen bygginfo";
"settings_flair" = "Visa emblem där det tillåts";
"settings_three_pids_management_information_part3" = ".";
"settings_integrations_allow_description" = "Använd en integrationshanterare (%@) för att hantera bottar, bryggor, widgets och dekalpaket.\n\nIntegrationshanterare får konfigurationsdata och kan modifiera widgets, skicka rumsinbjudningar och sätta behörighetsnivåer å dina vägnar.";
"settings_contacts_phonebook_country" = "Land för telefonbok";
"settings_key_backup_info_not_valid" = "Den här sessionen säkerhetskopierar inte dina nycklar, men du har en existerande säkerhetskopia du kan återställa från och lägga till i i framtiden.";
"settings_discovery_three_pids_management_information_part1" = "Hantera vilka e-postadresser eller telefonnummer andra användare kan använda för att upptäcka dig och att bjuda in dig till rum. Lägg till eller ta bort e-postadresser eller telefonnummer från listan i ";
"settings_discovery_three_pids_management_information_part3" = ".";
"settings_identity_server_description" = "Med hjälp av identitetsservern som anges ovan kan du upptäcka och upptäckas av befintliga kontakter du känner.";
"settings_identity_server_no_is_description" = "Du använder för närvarande inte en identitetsserver. För att upptäcka och bli upptäckt av befintliga kontakter du känner, lägg till en ovan.";
"security_settings_crypto_sessions_description_2" = "Om du inte känner igen en inloggning, ändra ditt lösenord och återställ säker säkerhetskopiering.";
"security_settings_secure_backup" = "SÄKER SÄKERHETSKOPIERING";
"security_settings_secure_backup_description" = "Skydda mot att förlora åtkomst till krypterade meddelanden och data genom att säkerhetskopiera krypteringsnycklar på din server.";
"security_settings_backup" = "MEDDELANDESÄKERHETSKOPIERING";
"security_settings_crosssigning_bootstrap" = "Ställ in korssignering";
"security_settings_complete_security_alert_title" = "Fullborda säkerhet";
"security_settings_coming_soon" = "Den här åtgärden är tyvärr inte tillgänglig i Element iOS än. Använd en annan Matrix-klient för att ställa in den. Element iOS kommer att använda den.";
"identity_server_settings_description" = "Du använder för närvarande %@ för att upptäcka och kunna upptäckas av befintliga kontakter du känner till.";
"identity_server_settings_no_is_description" = "Du använder för närvarande inte en identitetsserver. För att upptäcka och bli upptäckbar av befintliga kontakter, lägg till en ovan.";
"identity_server_settings_disconnect_info" = "Om du kopplar bort från din identitetsserver kan du inte bli upptäckt av andra användare eller bjuda in andra via e-post eller telefon.";
"identity_server_settings_alert_no_terms" = "Identitetsservern du har valt har inga användarvillkor. Fortsätt bara om du litar på serverns ägare.";
"identity_server_settings_alert_disconnect_button" = "Koppla från";
"identity_server_settings_alert_disconnect_still_sharing_3pid" = "Du delar fortfarande dina personuppgifter på identitetsservern %@.\n\nVi rekommenderar att du tar bort dina e-postadresser och telefonnummer från identitetsservern innan du kopplar från.";
"identity_server_settings_alert_disconnect_still_sharing_3pid_button" = "Koppla från ändå";
// Room Details
"room_details_title" = "Rumsdetaljer";
"room_details_photo" = "Rumsbild";
"room_details_access_section_anyone_apart_from_guest" = "Alla som har länken till rummet, förutom gäster";
"room_details_access_section_anyone" = "Alla som har länken till rummet, inklusive gäster";
"room_details_access_section_directory_toggle" = "Lista det här rummet i rumskatalogen";
"room_details_history_section_prompt_msg" = "Ändringar av vem som kan läsa historik gäller endast framtida meddelanden i detta rum. Synligheten för befintlig historik kommer att vara oförändrad.";
"room_details_addresses_disable_main_address_prompt_msg" = "Du kommer inte att ha någon huvudadress angiven. Standardhuvudadressen för detta rum väljs slumpmässigt";
"room_details_flair_section" = "Visa emblem för gemenskaper";
"room_details_new_flair_placeholder" = "Lägg till gemenskaps-ID (t.ex. +foo%@)";
"room_details_flair_invalid_id_prompt_msg" = "%@ är inte en giltig identifierare för en gemenskap";
"room_details_fail_to_update_avatar" = "Misslyckades att uppdatera rumsbilden";
"room_details_fail_to_update_room_name" = "Misslyckades att uppdatera rumsnamnet";
"room_details_fail_to_update_room_guest_access" = "Misslyckades att uppdatera rummets gäståtkomst";
"room_details_fail_to_update_room_join_rule" = "Misslyckades att uppdatera regeln för att gå med";
"room_details_fail_to_update_room_directory_visibility" = "Misslyckades att uppdatera rummets synlighet";
"room_details_unset_main_address" = "Sluta använd som huvudadress";
"room_details_copy_room_url" = "Kopiera rums-URL";
"group_participants_invited_section" = "INBJUDNA";
// Read Receipts
"read_receipts_list" = "Lista med läskvitton";
// Image picker
"image_picker_action_camera" = "Ta foto";
// Directory
"directory_title" = "Katalog";
"directory_server_picker_title" = "Välj en katalog";
"directory_server_all_rooms" = "Alla rum på servern %@";
"directory_server_type_homeserver" = "Skriv in en hemserver för att lista offentliga rum från";
"event_formatter_jitsi_widget_added" = "VoIP-gruppsamtal tillagt av %@";
"event_formatter_jitsi_widget_removed" = "VoIP-gruppsamtal borttaget av %@";
"event_formatter_rerequest_keys_part1_link" = "Begär krypteringsnycklar på nytt";
"event_formatter_rerequest_keys_part2" = " från dina andra sessioner.";
"event_formatter_message_edited_mention" = "(redigerat)";
"event_formatter_jitsi_widget_added_by_you" = "Du lade till VoIP-konferens";
"event_formatter_jitsi_widget_removed_by_you" = "Du tog bort VoIP-konferens";
"public_room_section_title" = "Offentliga rum (på %@):";
"bug_report_prompt" = "Appen har kraschat förra gången. Vill du skicka en kraschrapport?";
"camera_access_not_granted" = "%@ verkar inte ha behörighet att använda kameran, vänligen ändra integritetsinställningarna";
"photo_library_access_not_granted" = "%@ verkar inte ha åtkomst till bildbiblioteket, vänligen ändra integritetsinställningarna";
"large_badge_value_k_format" = "%.1fK";
"call_incoming_voice" = "Inkommande samtal…";
"call_incoming_video" = "Inkommande videosamtal…";
"call_already_displayed" = "Ett samtal pågår redan.";
"call_no_stun_server_error_use_fallback_button" = "Försök att använda %@";
// Crypto
"e2e_enabling_on_app_update" = "Element har nu stöd för totalsträckskryptering men du behöver logga in igen för att aktivera det.\n\nDu kan göra det nu eller senare från appens inställningar.";
"bug_report_send_screenshot" = "Skicka skärmdump";
"widget_no_power_to_manage" = "Du behöver behörighet för att hantera widgets i det här rummet";
"widget_creation_failure" = "Skapande av widget har misslyckats";
"widget_menu_refresh" = "Ladda om";
"widget_menu_revoke_permission" = "Återkalla åtkomst för mig";
"widget_integration_unable_to_create" = "Kunde inte skapa widget.";
"widget_integration_failed_to_send_request" = "Misslyckades att skicka begäran.";
"widget_integration_missing_room_id" = "Begäran saknar room_id.";
"widget_integration_missing_user_id" = "Begäran saknar user_id.";
"widget_integration_room_not_visible" = "Rummet %@ är inte synligt.";
// Widget Picker
"widget_picker_title" = "Integrationer";
"widget_picker_manage_integrations" = "Hantera integrationer…";
// Room widget permissions
"room_widget_permission_title" = "Läs in widget";
"room_widget_permission_creator_info_title" = "Den här widgeten lades till av:";
// Share extension
"share_extension_auth_prompt" = "Logga in i huvudappen för att dela innehåll";
// Room key request dialog
"e2e_room_key_request_title" = "Begäran om krypteringsnyckel";
"e2e_room_key_request_start_verification" = "Starta verifiering…";
"e2e_room_key_request_share_without_verifying" = "Dela utan att verifiera";
// GDPR
"gdpr_consent_not_given_alert_message" = "För att fortsätta använda hemservern %@ behöver du ta del av och godkänna villkoren.";
"service_terms_modal_message" = "För att fortsätta behöver du godkänna villkoren för den här tjänsten (%@).";
"service_terms_modal_description_for_identity_server_2" = "Hitta mig via telefon eller e-post";
// Service terms - Variant for identity server when displayed out of a context
"service_terms_modal_title_identity_server" = "Upptäckt av kontakter";
"service_terms_modal_policy_checkbox_accessibility_hint" = "Kryssa i för att godkänna %@";
"deactivate_account_informations_part1" = "Detta kommer att göra ditt konto permanent oanvändbart. Du kommer inte att kunna logga in, och ingen kommer att kunna registrera på nytt med samma användar-ID. Detta kommer innebära att ditt konto lämnar alla rum det deltar i, och dina kontouppgifter kommer att tas bort från din identitetsserver. ";
"deactivate_account_informations_part2_emphasize" = "Denna åtgärd går inte att ångra.";
"deactivate_account_informations_part3" = "\n\nAtt inaktivera ditt konto ";
"deactivate_account_informations_part4_emphasize" = "leder inte normalt till att vi glömmer meddelanden som du har skickat. ";
"deactivate_account_informations_part5" = "Om du vill att vi glömmer dina meddelanden, vänligen kryssa i rutan nedan\n\nSynlighet för meddelanden i Matrix liknar den i e-post. När vi glömmer dina meddelanden betyder det att meddelanden som du har skickat inte kommer att delas med några nya eller oregistrerade användare, men registrerade användare som redan har tillgång till dessa meddelanden kommer fortfarande ha tillgång till sin kopia.";
"deactivate_account_forget_messages_information_part1" = "Glöm alla meddelanden som jag har skickat när mitt konto inaktiveras (";
"deactivate_account_forget_messages_information_part3" = ": detta leder till att framtida användare kommer att se en ofullständig bild av konversationer)";
"deactivate_account_validate_action" = "Inaktivera konto";
"deactivate_account_password_alert_title" = "Inaktivera konto";
"deactivate_account_password_alert_message" = "För att fortsätta, ange ditt lösenord";
"rerequest_keys_alert_message" = "Starta Element på en annan enhet som dekryptera meddelandet så att den kan skicka nycklarna till den här sessionen.";
"secure_key_backup_setup_intro_use_security_key_title" = "Använd en säkerhetsnyckel";
"secure_key_backup_setup_intro_use_security_key_info" = "Generera en säkerhetsnyckel att lagra på en säker plats, exempelvis i en lösenordshanterare eller ett kassaskåp.";
"secure_key_backup_setup_existing_backup_error_unlock_it" = "Lås upp den";
"secure_key_backup_setup_existing_backup_error_delete_it" = "Radera den";
"secure_key_backup_setup_cancel_alert_title" = "Är du säker?";
"secure_backup_setup_banner_title" = "Säker säkerhetskopia";
"key_backup_setup_title" = "Nyckelsäkerhetskopiering";
"key_backup_setup_skip_alert_title" = "Är du säker?";
"key_backup_setup_skip_alert_message" = "Du kanske kommer förlora säkra meddelanden om du loggar ut från eller tappar bort din enhet.";
"key_backup_setup_skip_alert_skip_action" = "Hoppa över";
"key_backup_setup_intro_info" = "Meddelanden i krypterade rum skyddas av totalsträckskryptering. Endast du och mottagaren/mottagarna har nycklarna för att läsa dessa meddelanden.\n\nSäkerhetskopiera dina nycklar för att inte bli av med dem.";
"key_backup_setup_intro_manual_export_info" = "(Avancerat)";
"key_backup_setup_intro_manual_export_action" = "Exportera nycklar manuellt";
"key_backup_setup_passphrase_title" = "Skydda din säkerhetskopia med en lösenfras";
"key_backup_setup_passphrase_passphrase_title" = "Ange";
"key_backup_setup_passphrase_passphrase_placeholder" = "Ange lösenfras";
"key_backup_setup_passphrase_passphrase_valid" = "Toppen!";
"key_backup_setup_passphrase_passphrase_invalid" = "Försök att lägga till ett ord";
"key_backup_setup_passphrase_confirm_passphrase_title" = "Bekräfta";
"key_backup_setup_passphrase_confirm_passphrase_placeholder" = "Bekräfta lösenfras";
"key_backup_setup_passphrase_confirm_passphrase_valid" = "Toppen!";
"key_backup_setup_passphrase_confirm_passphrase_invalid" = "Lösenfrasen matchar inte";
"key_backup_setup_passphrase_set_passphrase_action" = "Ställ in lösenfras";
"key_backup_setup_passphrase_setup_recovery_key_action" = "(Avancerat) Ställ in med återställningsnyckel";
"key_backup_setup_success_title" = "Lyckades!";
// Success from passphrase
"key_backup_setup_success_from_passphrase_info" = "Dina nycklar säkerhetskopieras.\n\nDin återställningsnyckel är ett skyddsnät du kan använda den för att åter få tillgång till dina krypterade meddelanden om du glömmer din lösenfras.\n\nLagra din återställningsnyckel på en väldigt säker plats, som i en lösenordshanterare (eller ett kassaskåp).";
"key_backup_setup_success_from_passphrase_save_recovery_key_action" = "Spara återställningsnyckel";
"key_backup_setup_success_from_passphrase_done_action" = "Klart";
// Success from recovery key
"key_backup_setup_success_from_recovery_key_info" = "Dina nycklar säkerhetskopieras.\n\nSkapa en kopia av den här återställningsnyckeln och skydda den.";
"key_backup_setup_success_from_recovery_key_recovery_key_title" = "Återställningsnyckel";
"key_backup_setup_success_from_recovery_key_make_copy_action" = "Skapa en kopia";
"key_backup_setup_success_from_recovery_key_made_copy_action" = "Jag har skapat en kopia";
"key_backup_recover_title" = "Säkra meddelanden";
"key_backup_recover_invalid_passphrase_title" = "Felaktig återställningslösenfras";
"key_backup_recover_from_passphrase_passphrase_title" = "Ange";
"key_backup_recover_from_passphrase_passphrase_placeholder" = "Ange lösenfras";
"key_backup_recover_from_passphrase_lost_passphrase_action_part1" = "Känner du inte till din lösenfras för återställning? Du kan ";
"key_backup_recover_from_passphrase_lost_passphrase_action_part2" = "använda din återställningsnyckel";
"key_backup_recover_from_passphrase_lost_passphrase_action_part3" = ".";
"key_backup_recover_from_recovery_key_recovery_key_title" = "Ange";
"key_backup_recover_from_recovery_key_recovery_key_placeholder" = "Ange återställningsnyckel";
"key_backup_recover_from_recovery_key_lost_recovery_key_action" = "Förlorat din återställningsnyckel? Du kan ställa in en ny i inställningarna.";
"key_backup_recover_done_action" = "Klart";
"sign_out_existing_key_backup_alert_title" = "Är du säker på att du vill logga ut?";
"sign_out_existing_key_backup_alert_sign_out_action" = "Logga ut";
"sign_out_non_existing_key_backup_alert_title" = "Du kommer att förlora åtkomst till dina krypterade meddelanden om du loggar ut nu";
"sign_out_non_existing_key_backup_alert_setup_secure_backup_action" = "Börja använd säker säkerhetskopiering";
"sign_out_non_existing_key_backup_alert_discard_key_backup_action" = "Jag vill inte ha mina krypterade meddelanden";
"sign_out_non_existing_key_backup_sign_out_confirmation_alert_title" = "Du kommer att förlora dina krypterade meddelanden";
"sign_out_non_existing_key_backup_sign_out_confirmation_alert_sign_out_action" = "Logga ut";
"sign_out_key_backup_in_progress_alert_discard_key_backup_action" = "Jag vill inte ha mina krypterade meddelanden";
"sign_out_key_backup_in_progress_alert_cancel_action" = "Jag väntar";
// MARK: - Device Verification
"key_verification_other_session_title" = "Verifiera session";
"key_verification_new_session_title" = "Verifiera din nya session";
"key_verification_this_session_title" = "Verifiera den här sessionen";
"key_verification_user_title" = "Verifiera dem";
"room_details_fail_to_update_room_communities" = "Misslyckades att uppdatera relaterade gemenskaper";
"room_details_fail_to_update_room_direct" = "Misslyckades att direktflaggan för rummet";
// Group Details
"group_details_title" = "Gemenskapsdetaljer";
"group_invitation_format" = "%@ har bjudit in dig att gå med i den här gemenskapen";
"receipt_status_read" = "Läst: ";
"directory_server_all_native_rooms" = "Alla nativa Matrixrum";
"call_jitsi_error" = "Misslyckades att gå med i gruppsamtalet.";
"call_no_stun_server_error_title" = "Samtalet misslyckades p.g.a. felkonfigurerad server";
"call_no_stun_server_error_message_1" = "Vänligen be administratören för hemservern %@ att konfigurera en TURN-server för att samtal ska funka tillförlitligt.";
"call_no_stun_server_error_message_2" = "Alternativt kan du försöka använda den offentliga servern på% @, men det här är inte lika tillförlitligt och det delar din IP-adress med den servern. Du kan också hantera detta i inställningarna";
"no_voip" = "%@ ringer dig men %@ stöder inte samtal än.\nDu kan ignorera den här aviseringen och svara på samtalet med en annan enhet eller avvisa det.";
// Crash report
"google_analytics_use_prompt" = "Vill du hjälpa till att förbättra %@ genom att automatiskt skicka anonyma kraschrapporter och användningsdata?";
"e2e_need_log_in_again" = "Du behöver logga in igen för att generera nycklar för totalsträckskryptering för den här sessionen och skicka den publika nyckeln till din hemserver.\nDet behövs bara en gång; beklagar olägenheten.";
"e2e_key_backup_wrong_version" = "En ny säkerhetskopia för säkra meddelandenycklar har upptäckts.\n\nOm det inte var du, ställ in en ny lösenfras i inställningarna.";
"bug_report_description" = "Vänligen beskriv buggen. Vad gjorde du? Vad förväntade du dig att hända? Vad hände egentligen?";
"bug_crash_report_description" = "Vänligen beskriv vad du gjorde innan kraschen:";
"bug_report_logs_description" = "För att diagnostisera problem skickas loggar från den här klienten med denna buggrapport. Om du föredrar att bara skicka texten ovan, kryssa ur:";
// Widget
"widget_no_integrations_server_configured" = "Ingen integrationsserver konfigurerad";
"widget_integrations_server_failed_to_connect" = "Misslyckades att ansluta till integrationsservern";
"widget_sticker_picker_no_stickerpacks_alert" = "Du har för närvarande inga dekalpaket aktiva.";
// Widget Integration Manager
"widget_integration_need_to_be_able_to_invite" = "Du behöver kunna bjuda in användare för att göra det där.";
"widget_integration_positive_power_level" = "Behörighetsnivå måste vara ett positivt heltal.";
"widget_integration_no_permission_in_room" = "Du har inte behörighet att göra det där i det här rummet.";
"widget_integration_manager_disabled" = "Du behöver aktivera integrationshanteraren i inställningarna";
"room_widget_permission_webview_information_title" = "Att använda den kan sätta kakor och dela data med %@:\n";
"room_widget_permission_information_title" = "Att använda den kan dela data med %@:\n";
"share_extension_failed_to_encrypt" = "Misslyckades att skicka. Kolla krypteringsinställningarna för det här rummet i huvudappen";
"e2e_room_key_request_message_new_device" = "Du lade till en ny session '%@' vilken begär krypteringsnycklar.";
"e2e_room_key_request_message" = "En overifierad session '%@' begär krypteringsnycklar.";
"e2e_room_key_request_ignore_request" = "Ignorera begäran";
"service_terms_modal_description_for_integration_manager" = "Använd bottar, bryggor, widgets och dekalpaket";
// Re-request confirmation dialog
"rerequest_keys_alert_title" = "Begäran skickad";
"secure_key_backup_setup_intro_title" = "Säker säkerhetskopia";
"secure_key_backup_setup_intro_info" = "Skydda mot att förlora åtkomst till krypterade meddelanden och data genom att säkerhetskopiera krypteringsnycklar på din server.";
"secure_key_backup_setup_intro_use_security_passphrase_title" = "Använd en säkerhetslösenfras";
"secure_key_backup_setup_intro_use_security_passphrase_info" = "Ange en hemlig fras endast du känner till, för att generera en nyckel för säkerhetskopiering.";
"secure_key_backup_setup_existing_backup_error_title" = "En säkerhetskopia för meddelanden finns redan";
"secure_key_backup_setup_existing_backup_error_info" = "Lås upp den för att återanvända den för säker säkerhetskopiering eller radera den för att skapa en ny säkerhetskopia för meddelanden i den säkra säkerhetskopieringen.";
"secure_key_backup_setup_cancel_alert_message" = "Om du avbryter nu kan du förlora krypterade meddelanden och data om du förlorar åtkomst till dina inloggningar.\n\nDu kan också ställa in säker säkerhetskopiering och hantera dina nycklar i inställningarna.";
"secure_backup_setup_banner_subtitle" = "Skydda mot att förlora åtkomst till krypterade meddelanden och data";
"key_backup_setup_intro_title" = "Bli aldrig av med krypterade meddelanden";
"key_backup_setup_intro_setup_action_without_existing_backup" = "Börja använda nyckelsäkerhetskopiering";
"key_backup_setup_intro_setup_connect_action_with_existing_backup" = "Anslut den här enheten till nyckelsäkerhetskopiering";
"key_backup_setup_passphrase_info" = "Vi kommer lagra en krypterad kopia av dina nycklar på vår server. Skydda din säkerhetskopia med en lösenfras för att hålla den säker.\n\nFör maximal säkerhet bör denna skilja sig från ditt kontolösenord.";
"key_backup_setup_passphrase_setup_recovery_key_info" = "Eller säkra din säkerhetskopia med en återställningsnyckel och spara den någonstans säkert.";
"key_backup_recover_invalid_passphrase" = "Säkerhetskopian kunde inte avkrypteras med den här lösenfrasen: vänligen kontrollera att du angav rätt återställningslösenfras.";
"key_backup_recover_invalid_recovery_key_title" = "Återställningsnyckel matchade inte";
"key_backup_recover_invalid_recovery_key" = "Säkerhetskopian kunde inte avkrypteras med den här nyckeln: vänligen kontrollera att du angav rätt återställningsnyckel.";
// Recover from private key
"key_backup_recover_from_private_key_info" = "Återställer säkerhetskopia…";
"key_backup_recover_from_passphrase_info" = "Använd din återställningslösenfras för att låsa upp din säkra meddelandehistorik";
"key_backup_recover_from_passphrase_recover_action" = "Lås upp historik";
"key_backup_recover_from_recovery_key_info" = "Använd din återställningsnyckel för att låsa upp din säkra meddelandehistorik";
"key_backup_recover_from_recovery_key_recover_action" = "Lås upp historik";
"key_backup_recover_success_info" = "Säkerhetskopia återställd!";
"sign_out_non_existing_key_backup_sign_out_confirmation_alert_message" = "Du förlorar åtkomst till dina krypterade meddelanden om du inte säkerhetskopierar dina nycklar innan du loggar ut.";
"sign_out_non_existing_key_backup_sign_out_confirmation_alert_backup_action" = "Säkerhetskopiera";
"sign_out_key_backup_in_progress_alert_title" = "Nyckelsäkerhetskopiering pågår. Om du loggar ut nu förlorar du åtkomsten till dina krypterade meddelanden.";
"device_verification_security_advice_emoji" = "Jämför de unika emojierna och försäkra dig om att de visas i samma ordning.";
"device_verification_security_advice_number" = "Jämför numren och försäkra dig om att de visas i samma ordning.";
"device_verification_cancelled" = "Den andra parten avbröt verifieringen.";
"device_verification_cancelled_by_me" = "Verifieringen har avbrutits. Orsak: %@";
"device_verification_error_cannot_load_device" = "Kan inte ladda sessionsinformation.";
// Mark: Incoming
"device_verification_incoming_title" = "Inkommande verifieringsbegäran";
"device_verification_incoming_description_1" = "Verifiera den här sessionen för att markera den som betrodd. Genom att lita på partnersessioner får du extra sinnesro när du använder totalsträckskrypterade meddelanden.";
"device_verification_incoming_description_2" = "Om du verifierar den här sessionen markeras den som betrodd och markerar också din session som betrodd för partnern.";
// MARK: Start
"device_verification_start_title" = "Verifiera genom att jämföra en kort textsträng";
"device_verification_start_wait_partner" = "Väntar på att partnern ska acceptera…";
"device_verification_start_use_legacy" = "Visas inget? Inte alla klienter stöder interaktiv verifiering än. Använd legacyverifiering.";
"device_verification_start_verify_button" = "Börja verifiera";
"device_verification_start_use_legacy_action" = "Använd legacyverifiering";
// New login
"device_verification_self_verify_alert_title" = "Ny inloggning. Var det du?";
"device_verification_self_verify_alert_message" = "Verifiera den nya inloggningen på ditt konto: %@";
"device_verification_self_verify_alert_validate_action" = "Verifiera";
"device_verification_self_verify_start_verify_action" = "Påbörja verifiering";
"device_verification_self_verify_start_information" = "Använd den här sessionen för att verifiera den nya och ge den åtkomst till krypterade meddelanden.";
"device_verification_self_verify_start_waiting" = "Väntar…";
"key_verification_self_verify_current_session_alert_title" = "Verifiera den här sessionen";
"key_verification_self_verify_current_session_alert_message" = "Andra användare kanske inte lita på den.";
"key_verification_self_verify_current_session_alert_validate_action" = "Verifiera";
"key_verification_self_verify_unverified_sessions_alert_title" = "Granska var du är inloggad";
"key_verification_self_verify_unverified_sessions_alert_message" = "Verifiera alla dina sessioner för att försäkra att ditt konto och dina meddelanden är säkra.";
"key_verification_self_verify_unverified_sessions_alert_validate_action" = "Granska";
"device_verification_self_verify_wait_title" = "Fullgör säkerhet";
"device_verification_self_verify_wait_new_sign_in_title" = "Verifiera den här inloggningen";
"device_verification_self_verify_wait_information" = "Verifiera den här sessionen från en av dina andra sessioner och ge den åtkomst till krypterade meddelanden.\n\nAnvänd senaste Element på dina andra enheter:";
"device_verification_self_verify_wait_recover_secrets_without_passphrase" = "Använd återställningsnyckel";
"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "Använd återställningslösenfras eller -nyckel";
"device_verification_self_verify_wait_recover_secrets_additional_information" = "Om du inte kan komma åt en existerade session";
"key_verification_verify_sas_title_emoji" = "Jämför emojier";
"key_verification_verify_sas_title_number" = "Jämför nummer";
"key_verification_verify_sas_cancel_action" = "De matchar inte";
"key_verification_verify_sas_validate_action" = "De matchar";
"key_verification_verify_sas_additional_information" = "För maximal säkerhet, använd en annan pålitlig form av kommunikation eller gör det här personligen.";
"key_verification_manually_verify_device_title" = "Verifiera manuellt med text";
"key_verification_manually_verify_device_instruction" = "Bekräfta genom att jämföra följande med användarinställningarna i din andra session:";
"key_verification_manually_verify_device_name_title" = "Sessionsnamn";
"key_verification_manually_verify_device_id_title" = "Sessions-ID";
"key_verification_manually_verify_device_key_title" = "Sessonsnyckel";
"key_verification_manually_verify_device_additional_information" = "Om de inte matchar så kan säkerheten för din kommunikation vara äventyrad.";
"key_verification_manually_verify_device_validate_action" = "Verifiera";
"device_verification_verify_wait_partner" = "Väntar på att partnern ska bekräfta…";
"device_verification_verified_title" = "Verifierad!";
"device_verification_verified_got_it_button" = "Förstått";
"key_verification_verified_new_session_title" = "Ny session verifierad!";
"key_verification_verified_other_session_information" = "Du kan nu läsa säkra meddelanden på din andra session, och andra användare kommer att lita på den.";
"key_verification_verified_new_session_information" = "Du kan nu läsa säkra meddelanden på din nya enhet, och andra användare kommer att lita på den.";
"key_verification_verified_this_session_information" = "Du kan nu läsa säkra meddelanden på den här enheten, och andra användare kommer att lita på den.";
"key_verification_verified_user_information" = "Meddelanden med den här användaren är totalsträckskrypterade och kan inte läsas av tredje parter.";
// MARK: Emoji
"device_verification_emoji_dog" = "Hund";
"device_verification_emoji_cat" = "Katt";
"device_verification_emoji_lion" = "Lejon";
"device_verification_emoji_horse" = "Häst";
"device_verification_emoji_unicorn" = "Enhörning";
"device_verification_emoji_pig" = "Gris";
"device_verification_emoji_elephant" = "Elefant";
"device_verification_emoji_rabbit" = "Kanin";
"device_verification_emoji_panda" = "Panda";
"device_verification_emoji_rooster" = "Tupp";
"device_verification_emoji_penguin" = "Pingvin";
"device_verification_emoji_turtle" = "Sköldpadda";
"device_verification_emoji_fish" = "Fisk";
"device_verification_emoji_octopus" = "Bläckfisk";
"device_verification_emoji_butterfly" = "Fjäril";
"device_verification_emoji_flower" = "Blomma";
"device_verification_emoji_tree" = "Träd";
"device_verification_emoji_cactus" = "Kaktus";
"device_verification_emoji_mushroom" = "Svamp";
"device_verification_emoji_globe" = "Jordklot";
"device_verification_emoji_moon" = "Måne";
"device_verification_emoji_cloud" = "Moln";
"device_verification_emoji_fire" = "Eld";
"device_verification_emoji_banana" = "Banan";
"device_verification_emoji_apple" = "Äpple";
"device_verification_emoji_strawberry" = "Jordgubbe";
"device_verification_emoji_corn" = "Majs";
"device_verification_emoji_pizza" = "Pizza";
"device_verification_emoji_cake" = "Tårta";
"device_verification_emoji_heart" = "Hjärta";
"device_verification_emoji_smiley" = "Smiley";
"device_verification_emoji_robot" = "Robot";
"device_verification_emoji_hat" = "Hatt";
"device_verification_emoji_glasses" = "Glasögon";
"device_verification_emoji_spanner" = "Skruvnyckel";
"device_verification_emoji_santa" = "Tomte";
"device_verification_emoji_thumbs up" = "Tummen upp";
"device_verification_emoji_umbrella" = "Paraply";
"device_verification_emoji_hourglass" = "Timglas";
"device_verification_emoji_clock" = "Klocka";
"device_verification_emoji_gift" = "Present";
"device_verification_emoji_light bulb" = "Lampa";
"device_verification_emoji_book" = "Bok";
"device_verification_emoji_pencil" = "Penna";
"device_verification_emoji_paperclip" = "Gem";
"device_verification_emoji_scissors" = "Sax";
"device_verification_emoji_lock" = "Lås";
"device_verification_emoji_key" = "Nyckel";
"device_verification_emoji_hammer" = "Hammare";
"device_verification_emoji_telephone" = "Telefon";
"device_verification_emoji_flag" = "Flagga";
"device_verification_emoji_train" = "Tåg";
"device_verification_emoji_bicycle" = "Cykel";
"device_verification_emoji_aeroplane" = "Flygplan";
"device_verification_emoji_rocket" = "Raket";
"device_verification_emoji_trophy" = "Trofé";
"device_verification_emoji_ball" = "Boll";
"device_verification_emoji_guitar" = "Gitarr";
"device_verification_emoji_trumpet" = "Trumpet";
"device_verification_emoji_bell" = "Bjällra";
"device_verification_emoji_anchor" = "Ankare";
"device_verification_emoji_headphones" = "Hörlurar";
"device_verification_emoji_folder" = "Mapp";
"device_verification_emoji_pin" = "Häftstift";
// MARK: File upload
"file_upload_error_title" = "Filuppladdning";
"file_upload_error_unsupported_file_type_message" = "Filtyp stöds inte.";
// MARK: Emoji picker
"emoji_picker_title" = "Reaktioner";
"emoji_picker_people_category" = "Smileys & personer";
"emoji_picker_nature_category" = "Djur & natur";
"emoji_picker_foods_category" = "Mat & dryck";
"emoji_picker_activity_category" = "Aktiviteter";
"emoji_picker_places_category" = "Resor & platser";
"emoji_picker_objects_category" = "Saker";
"emoji_picker_symbols_category" = "Symboler";
"emoji_picker_flags_category" = "Flaggor";
// MARK: Reaction history
"reaction_history_title" = "Reaktioner";
"error_not_supported_on_mobile" = "Du kan inte göra detta från %@ på mobilen.";
"key_verification_bootstrap_not_setup_title" = "Fel";
"key_verification_bootstrap_not_setup_message" = "Du behöver sätta upp korssignering först.";
"key_verification_tile_request_incoming_title" = "Verifieringsbegäran";
"key_verification_tile_request_outgoing_title" = "Verifiering skickad";
"key_verification_tile_request_status_data_loading" = "Data laddas…";
"key_verification_tile_request_status_waiting" = "Väntar…";
"key_verification_tile_request_status_expired" = "Utlöpt";
"key_verification_tile_request_status_cancelled_by_me" = "Du avbröt";
"key_verification_tile_request_status_cancelled" = "%@ avbröt";
"key_verification_tile_request_status_accepted" = "Du accepterade";
"key_verification_tile_request_incoming_approval_accept" = "Godkänn";
"key_verification_tile_request_incoming_approval_decline" = "Avböj";
"key_verification_tile_conclusion_done_title" = "Verifierad";
"key_verification_tile_conclusion_warning_title" = "Obetrodd inloggning";
"key_verification_incoming_request_incoming_alert_message" = "%@ vill verifiera";
"key_verification_verify_qr_code_title" = "Verifiera genom att skanna";
"key_verification_verify_qr_code_information" = "Skanna koden genom att verifiera varandra säkert.";
"key_verification_verify_qr_code_information_other_device" = "Skanna koden nedan för att verifiera:";
"key_verification_verify_qr_code_emoji_information" = "Verifiera genom att jämföra unika emojier.";
"key_verification_verify_qr_code_scan_code_action" = "Skanna deras kod";
"key_verification_verify_qr_code_cannot_scan_action" = "Kan inte skanna?";
"key_verification_verify_qr_code_start_emoji_action" = "Verifiera med emoji";
"key_verification_verify_qr_code_other_scan_my_code_title" = "Lyckades den andra användaren skanna QR-koden?";
"key_verification_verify_qr_code_scan_other_code_success_title" = "Kod validerad!";
"key_verification_verify_qr_code_scan_other_code_success_message" = "QR-koden har validerats framgångsrikt.";
// Scanning
"key_verification_scan_confirmation_scanning_title" = "Nästan klar! Väntar på bekräftelse…";
"key_verification_scan_confirmation_scanning_user_waiting_other" = "Väntar på %@…";
"key_verification_scan_confirmation_scanning_device_waiting_other" = "Väntar på den andra enheten…";
// Scanned
"key_verification_scan_confirmation_scanned_title" = "Nästan klar!";
"key_verification_scan_confirmation_scanned_user_information" = "Visar %@ samma sköld?";
"key_verification_scan_confirmation_scanned_device_information" = "Visar den andra enheten samma sköld?";
"user_verification_start_verify_action" = "Påbörja verifiering";
"user_verification_start_information_part1" = "För extra säkerhet, verifiera ";
"user_verification_start_information_part2" = " genom att kolla en engångskod på båda dina enheter.";
"user_verification_start_waiting_partner" = "Väntar på %@…";
"user_verification_start_additional_information" = "För att vara säker, gör detta personligen eller använd en annan kommunikationsform.";
"user_verification_sessions_list_user_trust_level_trusted_title" = "Betrodd";
"user_verification_sessions_list_user_trust_level_warning_title" = "Varning";
"user_verification_sessions_list_user_trust_level_unknown_title" = "Okänd";
"user_verification_sessions_list_information" = "Meddelanden med den här användaren i det här rummet är totalsträckskrypterade och kan inte läsas av tredje parter.";
"user_verification_sessions_list_table_title" = "Sessioner";
"user_verification_sessions_list_session_trusted" = "Betrodd";
"user_verification_sessions_list_session_untrusted" = "Ej betrodd";
"user_verification_session_details_trusted_title" = "Betrodd";
"user_verification_session_details_untrusted_title" = "Ej betrodd";
"user_verification_session_details_information_trusted_current_user" = "Den här sessionen är betrodd för säkra meddelanden eftersom du verifierade den:";
"user_verification_session_details_information_trusted_other_user_part1" = "Den här sessionen är betrodd för säkra meddelanden eftersom ";
"user_verification_session_details_information_trusted_other_user_part2" = " verifierade den:";
"user_verification_session_details_information_untrusted_current_user" = "Verifiera den här sessionen för att markera den som betrodd och ge den åtkomst till krypterade meddelanden:";
"user_verification_session_details_information_untrusted_other_user" = " loggade in med en ny session:";
"user_verification_session_details_additional_information_untrusted_other_user" = "Tills den här användaren litar på den här sessionen kommer meddelanden till och från den att markeras med varningar. Alternativt kan du verifiera den manuellt.";
"user_verification_session_details_additional_information_untrusted_current_user" = "Om det inte var du som loggade in i den här sessionen så kan ditt konto vara äventyrat.";
"user_verification_session_details_verify_action_current_user" = "Interaktiv verifiering";
"user_verification_session_details_verify_action_current_user_manually" = "Verifiera manuellt med text";
"user_verification_session_details_verify_action_other_user" = "Verifiera manuellt";
"secrets_recovery_with_passphrase_title" = "Återställningslösenfras";
"secrets_recovery_with_passphrase_information_verify_device" = "Använd din återställningslösenfras för att verifiera den här enheten.";
"secrets_recovery_with_passphrase_passphrase_title" = "Ange";
"secrets_recovery_with_passphrase_passphrase_placeholder" = "Använd återställningslösenfras";
"secrets_recovery_with_passphrase_recover_action" = "Använd lösenfras";
"secrets_recovery_with_passphrase_lost_passphrase_action_part1" = "Känner du inte till din återställningslösenfras? Du kan ";
"secrets_recovery_with_passphrase_lost_passphrase_action_part2" = "använda din återställningsnyckel";
"secrets_recovery_with_passphrase_lost_passphrase_action_part3" = ".";
"secrets_recovery_with_passphrase_invalid_passphrase_title" = "Kunde inte komma åt hemlig lagring";
"secrets_recovery_with_passphrase_invalid_passphrase_message" = "Vänligen verifiera att du angav rätt återställningslösenfras.";
"secrets_recovery_with_key_title" = "Återställningsnyckel";
"secrets_recovery_with_key_information_verify_device" = "Använd din återställningsnyckel för att verifiera den här enheten.";
"secrets_recovery_with_key_recovery_key_title" = "Ange";
"secrets_recovery_with_key_recovery_key_placeholder" = "Ange återställningsnyckel";
"secrets_recovery_with_key_recover_action" = "Använd nyckel";
"secrets_recovery_with_key_invalid_recovery_key_title" = "Kunde inte komma åt hemlig lagring";
"secrets_recovery_with_key_invalid_recovery_key_message" = "Vänligen verifiera att du angav rätt återställningsnyckel.";
"secrets_setup_recovery_key_title" = "Spara din säkerhetsnyckel";
"secrets_setup_recovery_key_information" = "Lagra din återställningsnyckel någonstans säkert. Den kan användas för att låsa upp dina krypterade meddelanden och data.";
"secrets_setup_recovery_key_loading" = "Laddar…";
"secrets_setup_recovery_key_export_action" = "Spara";
"secrets_setup_recovery_key_done_action" = "Klart";
"secrets_setup_recovery_key_storage_alert_title" = "Håll den säker";
"secrets_setup_recovery_key_storage_alert_message" = "✓ Skriv ut den och förvara den säkert\n✓ Spara den på ett USB-minne eller säkerhetskopieringsenhet\n✓ Kopiera den till din personliga molnlagring";
"secrets_setup_recovery_passphrase_title" = "Sätt en säkerhetsfras";
"secrets_setup_recovery_passphrase_information" = "Ange en säkerhetsfras endast du känner till vilken används för att säkra hemligheter på din server.";
"secrets_setup_recovery_passphrase_additional_information" = "Använd inte ditt kontolösenord.";
"secrets_setup_recovery_passphrase_validate_action" = "Klart";
"secrets_setup_recovery_passphrase_confirm_information" = "Ange din säkerhetsfras igen för att bekräfta den.";
"secrets_setup_recovery_passphrase_confirm_passphrase_title" = "Bekräfta";
"secrets_setup_recovery_passphrase_confirm_passphrase_placeholder" = "Bekräfta lösenfras";
"cross_signing_setup_banner_title" = "Ställ in kryptering";
"cross_signing_setup_banner_subtitle" = "Verifiera dina andra enheter enklare";
"major_update_title" = "Riot är nu Element";
"major_update_information" = "Vi är glada att meddela att vi har bytt namn! Din app är uppdaterad och du är inloggad på ditt konto.";
"major_update_learn_more_action" = "Lär dig mer";
"major_update_done_action" = "Förstått";
"pin_protection_choose_pin" = "Väl en PIN-kod för säkerhet";
"pin_protection_confirm_pin" = "Bekräfta din PIN-kod";
"pin_protection_confirm_pin_to_disable" = "Bekräfta PIN-kod för att inaktivera PIN-kod";
"pin_protection_enter_pin" = "Ange din PIN-kod";
"pin_protection_forgot_pin" = "Glömt PIN-kod";
"pin_protection_reset_alert_title" = "Återställ PIN-kod";
"pin_protection_reset_alert_message" = "För att återställa din PIN-kod så kommer du behöva logga in igen och skapa en ny";
"pin_protection_reset_alert_action_reset" = "Återställ";
"pin_protection_mismatch_error_title" = "PIN-koderna matchar inte";
"pin_protection_mismatch_error_message" = "Vänligen försök igen";
"pin_protection_mismatch_too_many_times_error_message" = "Om du inte kommer ihåg din PIN-kod, tryck på knappen \"Glömt PIN-kod\".";
"pin_protection_settings_section_header_x" = "PIN & %@";
"pin_protection_settings_section_footer" = "För att återställa din PIN-kod så behöver du logga in igen och skapa en ny.";
"pin_protection_settings_enabled_forced" = "PIN-kod aktiverad";
"pin_protection_settings_enable_pin" = "Aktivera PIN-kod";
"biometrics_mode_touch_id" = "Touch ID";
"biometrics_mode_face_id" = "Face ID";
"biometrics_settings_enable_x" = "Aktivera %@";
"biometrics_setup_title_x" = "Aktivera %@";
"biometrics_setup_enable_button_title_x" = "Aktivera %@";
"biometrics_setup_subtitle" = "Spara tid";
"biometrics_desetup_title_x" = "Inaktivera %@";
"biometrics_desetup_subtitle" = "Spara inte tid";
"biometrics_desetup_disable_button_title_x" = "Inaktivera %@";
"biometrics_usage_reason" = "Autentisering krävs för att komma åt appen";
"biometrics_cant_unlocked_alert_title" = "Kan inte låsa upp appen";
"biometrics_cant_unlocked_alert_message_x" = "För att låsa upp, använd %@ eller logga in igen och aktivera %@ igen";
"biometrics_cant_unlocked_alert_message_login" = "Logga in igen";
"biometrics_cant_unlocked_alert_message_retry" = "Försök igen";

View file

@ -42,4 +42,5 @@ extension UITableViewCell {
@objc func vc_setAccessoryDisclosureIndicatorWithCurrentTheme() {
self.vc_setAccessoryDisclosureIndicator(withTheme: ThemeService.shared().theme)
}
}

View file

@ -108,6 +108,7 @@ internal enum Asset {
internal static let secretsRecoveryPassphrase = ImageAsset(name: "secrets_recovery_passphrase")
internal static let secretsSetupKey = ImageAsset(name: "secrets_setup_key")
internal static let secretsSetupPassphrase = ImageAsset(name: "secrets_setup_passphrase")
internal static let secretsResetWarning = ImageAsset(name: "secrets_reset_warning")
internal static let removeIconPink = ImageAsset(name: "remove_icon_pink")
internal static let settingsIcon = ImageAsset(name: "settings_icon")
internal static let tabFavourites = ImageAsset(name: "tab_favourites")

View file

@ -35,7 +35,6 @@ internal enum InfoPlist {
internal static let nsSiriUsageDescription: String = _document["NSSiriUsageDescription"]
internal static let uiBackgroundModes: [String] = _document["UIBackgroundModes"]
internal static let uiLaunchStoryboardName: String = _document["UILaunchStoryboardName"]
internal static let uiMainStoryboardFile: String = _document["UIMainStoryboardFile"]
internal static let uiRequiredDeviceCapabilities: [String] = _document["UIRequiredDeviceCapabilities"]
internal static let uiStatusBarHidden: Bool = _document["UIStatusBarHidden"]
internal static let uiStatusBarTintParameters: [String: Any] = _document["UIStatusBarTintParameters"]

View file

@ -147,6 +147,11 @@ internal enum StoryboardScene {
internal static let initialScene = InitialSceneType<Riot.RoomCreationEventsModalViewController>(storyboard: RoomCreationEventsModalViewController.self)
}
internal enum RoomInfoListViewController: StoryboardType {
internal static let storyboardName = "RoomInfoListViewController"
internal static let initialScene = InitialSceneType<Riot.RoomInfoListViewController>(storyboard: RoomInfoListViewController.self)
}
internal enum SecretsRecoveryWithKeyViewController: StoryboardType {
internal static let storyboardName = "SecretsRecoveryWithKeyViewController"
@ -157,6 +162,11 @@ internal enum StoryboardScene {
internal static let initialScene = InitialSceneType<Riot.SecretsRecoveryWithPassphraseViewController>(storyboard: SecretsRecoveryWithPassphraseViewController.self)
}
internal enum SecretsResetViewController: StoryboardType {
internal static let storyboardName = "SecretsResetViewController"
internal static let initialScene = InitialSceneType<Riot.SecretsResetViewController>(storyboard: SecretsResetViewController.self)
}
internal enum SecretsSetupRecoveryKeyViewController: StoryboardType {
internal static let storyboardName = "SecretsSetupRecoveryKeyViewController"

View file

@ -338,10 +338,6 @@ internal enum VectorL10n {
internal static func biometricsDesetupDisableButtonTitleX(_ p1: String) -> String {
return VectorL10n.tr("Vector", "biometrics_desetup_disable_button_title_x", p1)
}
///
internal static var biometricsDesetupSubtitle: String {
return VectorL10n.tr("Vector", "biometrics_desetup_subtitle")
}
/// Disable %@
internal static func biometricsDesetupTitleX(_ p1: String) -> String {
return VectorL10n.tr("Vector", "biometrics_desetup_title_x", p1)
@ -2038,10 +2034,18 @@ internal enum VectorL10n {
internal static func photoLibraryAccessNotGranted(_ p1: String) -> String {
return VectorL10n.tr("Vector", "photo_library_access_not_granted", p1)
}
/// Choose a PIN for security
/// Create a PIN for security
internal static var pinProtectionChoosePin: String {
return VectorL10n.tr("Vector", "pin_protection_choose_pin")
}
/// Welcome back.
internal static var pinProtectionChoosePinWelcomeAfterLogin: String {
return VectorL10n.tr("Vector", "pin_protection_choose_pin_welcome_after_login")
}
/// Welcome.
internal static var pinProtectionChoosePinWelcomeAfterRegister: String {
return VectorL10n.tr("Vector", "pin_protection_choose_pin_welcome_after_register")
}
/// Confirm your PIN
internal static var pinProtectionConfirmPin: String {
return VectorL10n.tr("Vector", "pin_protection_confirm_pin")
@ -2054,10 +2058,18 @@ internal enum VectorL10n {
internal static var pinProtectionEnterPin: String {
return VectorL10n.tr("Vector", "pin_protection_enter_pin")
}
/// Setting up a PIN lets you protect data like messages and contacts, so only you can access them by entering the PIN at the start of the app.
internal static var pinProtectionExplanatory: String {
return VectorL10n.tr("Vector", "pin_protection_explanatory")
}
/// Forgot PIN
internal static var pinProtectionForgotPin: String {
return VectorL10n.tr("Vector", "pin_protection_forgot_pin")
}
/// Too many errors, you've been logged out
internal static var pinProtectionKickUserAlertMessage: String {
return VectorL10n.tr("Vector", "pin_protection_kick_user_alert_message")
}
/// Please try again
internal static var pinProtectionMismatchErrorMessage: String {
return VectorL10n.tr("Vector", "pin_protection_mismatch_error_message")
@ -2070,6 +2082,10 @@ internal enum VectorL10n {
internal static var pinProtectionMismatchTooManyTimesErrorMessage: String {
return VectorL10n.tr("Vector", "pin_protection_mismatch_too_many_times_error_message")
}
/// For security reasons, this PIN isnt available. Please try another PIN
internal static var pinProtectionNotAllowedPin: String {
return VectorL10n.tr("Vector", "pin_protection_not_allowed_pin")
}
/// Reset
internal static var pinProtectionResetAlertActionReset: String {
return VectorL10n.tr("Vector", "pin_protection_reset_alert_action_reset")
@ -2270,10 +2286,26 @@ internal enum VectorL10n {
internal static var roomDetailsAccessSectionAnyoneApartFromGuest: String {
return VectorL10n.tr("Vector", "room_details_access_section_anyone_apart_from_guest")
}
/// Anyone who knows the link, apart from guests
internal static var roomDetailsAccessSectionAnyoneApartFromGuestForDm: String {
return VectorL10n.tr("Vector", "room_details_access_section_anyone_apart_from_guest_for_dm")
}
/// Anyone who knows the link, including guests
internal static var roomDetailsAccessSectionAnyoneForDm: String {
return VectorL10n.tr("Vector", "room_details_access_section_anyone_for_dm")
}
/// List this room in room directory
internal static var roomDetailsAccessSectionDirectoryToggle: String {
return VectorL10n.tr("Vector", "room_details_access_section_directory_toggle")
}
/// List in room directory
internal static var roomDetailsAccessSectionDirectoryToggleForDm: String {
return VectorL10n.tr("Vector", "room_details_access_section_directory_toggle_for_dm")
}
/// Who can access this?
internal static var roomDetailsAccessSectionForDm: String {
return VectorL10n.tr("Vector", "room_details_access_section_for_dm")
}
/// Only people who have been invited
internal static var roomDetailsAccessSectionInvitedOnly: String {
return VectorL10n.tr("Vector", "room_details_access_section_invited_only")
@ -2310,10 +2342,18 @@ internal enum VectorL10n {
internal static var roomDetailsAdvancedE2eEncryptionDisabled: String {
return VectorL10n.tr("Vector", "room_details_advanced_e2e_encryption_disabled")
}
/// Encryption is not enabled here.
internal static var roomDetailsAdvancedE2eEncryptionDisabledForDm: String {
return VectorL10n.tr("Vector", "room_details_advanced_e2e_encryption_disabled_for_dm")
}
/// Encryption is enabled in this room
internal static var roomDetailsAdvancedE2eEncryptionEnabled: String {
return VectorL10n.tr("Vector", "room_details_advanced_e2e_encryption_enabled")
}
/// Encryption is enabled here
internal static var roomDetailsAdvancedE2eEncryptionEnabledForDm: String {
return VectorL10n.tr("Vector", "room_details_advanced_e2e_encryption_enabled_for_dm")
}
/// Enable encryption (warning: cannot be disabled again!)
internal static var roomDetailsAdvancedEnableE2eEncryption: String {
return VectorL10n.tr("Vector", "room_details_advanced_enable_e2e_encryption")
@ -2322,6 +2362,10 @@ internal enum VectorL10n {
internal static var roomDetailsAdvancedRoomId: String {
return VectorL10n.tr("Vector", "room_details_advanced_room_id")
}
/// ID:
internal static var roomDetailsAdvancedRoomIdForDm: String {
return VectorL10n.tr("Vector", "room_details_advanced_room_id_for_dm")
}
/// Advanced
internal static var roomDetailsAdvancedSection: String {
return VectorL10n.tr("Vector", "room_details_advanced_section")
@ -2402,7 +2446,7 @@ internal enum VectorL10n {
internal static var roomDetailsFavouriteTag: String {
return VectorL10n.tr("Vector", "room_details_favourite_tag")
}
/// Files
/// Uploads
internal static var roomDetailsFiles: String {
return VectorL10n.tr("Vector", "room_details_files")
}
@ -2470,6 +2514,10 @@ internal enum VectorL10n {
internal static var roomDetailsNoLocalAddresses: String {
return VectorL10n.tr("Vector", "room_details_no_local_addresses")
}
/// This has no local addresses
internal static var roomDetailsNoLocalAddressesForDm: String {
return VectorL10n.tr("Vector", "room_details_no_local_addresses_for_dm")
}
/// Members
internal static var roomDetailsPeople: String {
return VectorL10n.tr("Vector", "room_details_people")
@ -2478,10 +2526,18 @@ internal enum VectorL10n {
internal static var roomDetailsPhoto: String {
return VectorL10n.tr("Vector", "room_details_photo")
}
/// Photo
internal static var roomDetailsPhotoForDm: String {
return VectorL10n.tr("Vector", "room_details_photo_for_dm")
}
/// Room Name
internal static var roomDetailsRoomName: String {
return VectorL10n.tr("Vector", "room_details_room_name")
}
/// Name
internal static var roomDetailsRoomNameForDm: String {
return VectorL10n.tr("Vector", "room_details_room_name_for_dm")
}
/// Do you want to save changes?
internal static var roomDetailsSaveChangesPrompt: String {
return VectorL10n.tr("Vector", "room_details_save_changes_prompt")
@ -2498,6 +2554,10 @@ internal enum VectorL10n {
internal static var roomDetailsTitle: String {
return VectorL10n.tr("Vector", "room_details_title")
}
/// Details
internal static var roomDetailsTitleForDm: String {
return VectorL10n.tr("Vector", "room_details_title_for_dm")
}
/// Topic
internal static var roomDetailsTopic: String {
return VectorL10n.tr("Vector", "room_details_topic")
@ -2618,6 +2678,18 @@ internal enum VectorL10n {
internal static var roomEventFailedToSend: String {
return VectorL10n.tr("Vector", "room_event_failed_to_send")
}
/// 1 member
internal static var roomInfoListOneMember: String {
return VectorL10n.tr("Vector", "room_info_list_one_member")
}
/// Other
internal static var roomInfoListSectionOther: String {
return VectorL10n.tr("Vector", "room_info_list_section_other")
}
/// %@ members
internal static func roomInfoListSeveralMembers(_ p1: String) -> String {
return VectorL10n.tr("Vector", "room_info_list_several_members", p1)
}
/// Jump to first unread message
internal static var roomJumpToFirstUnread: String {
return VectorL10n.tr("Vector", "room_jump_to_first_unread")
@ -2810,6 +2882,10 @@ internal enum VectorL10n {
internal static var roomParticipantsFilterRoomMembers: String {
return VectorL10n.tr("Vector", "room_participants_filter_room_members")
}
/// Filter members
internal static var roomParticipantsFilterRoomMembersForDm: String {
return VectorL10n.tr("Vector", "room_participants_filter_room_members_for_dm")
}
/// Idle
internal static var roomParticipantsIdle: String {
return VectorL10n.tr("Vector", "room_participants_idle")
@ -2842,10 +2918,18 @@ internal enum VectorL10n {
internal static var roomParticipantsLeavePromptMsg: String {
return VectorL10n.tr("Vector", "room_participants_leave_prompt_msg")
}
/// Are you sure you want to leave?
internal static var roomParticipantsLeavePromptMsgForDm: String {
return VectorL10n.tr("Vector", "room_participants_leave_prompt_msg_for_dm")
}
/// Leave room
internal static var roomParticipantsLeavePromptTitle: String {
return VectorL10n.tr("Vector", "room_participants_leave_prompt_title")
}
/// Leave
internal static var roomParticipantsLeavePromptTitleForDm: String {
return VectorL10n.tr("Vector", "room_participants_leave_prompt_title_for_dm")
}
/// %d participants
internal static func roomParticipantsMultiParticipants(_ p1: Int) -> String {
return VectorL10n.tr("Vector", "room_participants_multi_participants", p1)
@ -2882,10 +2966,18 @@ internal enum VectorL10n {
internal static var roomParticipantsSecurityInformationRoomEncrypted: String {
return VectorL10n.tr("Vector", "room_participants_security_information_room_encrypted")
}
/// Messages here 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 roomParticipantsSecurityInformationRoomEncryptedForDm: String {
return VectorL10n.tr("Vector", "room_participants_security_information_room_encrypted_for_dm")
}
/// 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")
}
/// Messages here are not end-to-end encrypted.
internal static var roomParticipantsSecurityInformationRoomNotEncryptedForDm: String {
return VectorL10n.tr("Vector", "room_participants_security_information_room_not_encrypted_for_dm")
}
/// Loading
internal static var roomParticipantsSecurityLoading: String {
return VectorL10n.tr("Vector", "room_participants_security_loading")
@ -3162,6 +3254,14 @@ internal enum VectorL10n {
internal static func searchableDirectoryXNetwork(_ p1: String) -> String {
return VectorL10n.tr("Vector", "searchable_directory_x_network", p1)
}
/// Forgot or lost all recovery options?
internal static var secretsRecoveryResetActionPart1: String {
return VectorL10n.tr("Vector", "secrets_recovery_reset_action_part_1")
}
/// Reset everything
internal static var secretsRecoveryResetActionPart2: String {
return VectorL10n.tr("Vector", "secrets_recovery_reset_action_part_2")
}
/// Access your secure message history and your cross-signing identity for verifying other sessions by entering your recovery key.
internal static var secretsRecoveryWithKeyInformationDefault: String {
return VectorL10n.tr("Vector", "secrets_recovery_with_key_information_default")
@ -3238,6 +3338,30 @@ internal enum VectorL10n {
internal static var secretsRecoveryWithPassphraseTitle: String {
return VectorL10n.tr("Vector", "secrets_recovery_with_passphrase_title")
}
/// Enter your account password to confirm
internal static var secretsResetAuthenticationMessage: String {
return VectorL10n.tr("Vector", "secrets_reset_authentication_message")
}
/// Only do this if you have no other device you can verify this device with.
internal static var secretsResetInformation: String {
return VectorL10n.tr("Vector", "secrets_reset_information")
}
/// Reset
internal static var secretsResetResetAction: String {
return VectorL10n.tr("Vector", "secrets_reset_reset_action")
}
/// Reset everything
internal static var secretsResetTitle: String {
return VectorL10n.tr("Vector", "secrets_reset_title")
}
/// You will restart with no history, no messages, trusted devices or trusted users.
internal static var secretsResetWarningMessage: String {
return VectorL10n.tr("Vector", "secrets_reset_warning_message")
}
/// If you reset everything
internal static var secretsResetWarningTitle: String {
return VectorL10n.tr("Vector", "secrets_reset_warning_title")
}
/// Done
internal static var secretsSetupRecoveryKeyDoneAction: String {
return VectorL10n.tr("Vector", "secrets_setup_recovery_key_done_action")

View file

@ -23,11 +23,13 @@ protocol KeyValueStore {
func set(_ value: Data?, forKey key: KeyValueStoreKey) throws
func set(_ value: String?, forKey key: KeyValueStoreKey) throws
func set(_ value: Bool?, forKey key: KeyValueStoreKey) throws
func set(_ value: Int?, forKey key: KeyValueStoreKey) throws
// getters
func data(forKey key: KeyValueStoreKey) throws -> Data?
func string(forKey key: KeyValueStoreKey) throws -> String?
func bool(forKey key: KeyValueStoreKey) throws -> Bool?
func integer(forKey key: KeyValueStoreKey) throws -> Int?
// remove
func removeObject(forKey key: KeyValueStoreKey) throws

View file

@ -76,6 +76,15 @@ extension KeychainStore: KeyValueStore {
try keychain.set(value, key: key)
}
func set(_ value: Int?, forKey key: KeyValueStoreKey) throws {
guard let value = value else {
try removeObject(forKey: key)
return
}
try keychain.set(String(value), key: key)
}
// getters
func data(forKey key: KeyValueStoreKey) throws -> Data? {
return try keychain.getData(key)
@ -89,6 +98,13 @@ extension KeychainStore: KeyValueStore {
return try keychain.getBool(key)
}
func integer(forKey key: KeyValueStoreKey) throws -> Int? {
guard let stringValue = try keychain.getString(key) else {
return nil
}
return Int(stringValue)
}
// remove
func removeObject(forKey key: KeyValueStoreKey) throws {
try keychain.remove(key)

View file

@ -49,6 +49,10 @@ extension MemoryStore: KeyValueStore {
setObject(value, forKey: key)
}
func set(_ value: Int?, forKey key: KeyValueStoreKey) throws {
setObject(value, forKey: key)
}
// getters
func data(forKey key: KeyValueStoreKey) throws -> Data? {
return object(forKey: key) as? Data
@ -62,6 +66,10 @@ extension MemoryStore: KeyValueStore {
return object(forKey: key) as? Bool
}
func integer(forKey key: KeyValueStoreKey) throws -> Int? {
return object(forKey: key) as? Int
}
// remove
func removeObject(forKey key: KeyValueStoreKey) {
map.removeValue(forKey: key)

View file

@ -15,6 +15,7 @@
//
import Foundation
import MatrixKit
@objcMembers
class LocalAuthenticationService: NSObject {
@ -63,5 +64,15 @@ class LocalAuthenticationService: NSObject {
func applicationWillResignActive() {
appLastActiveTime = systemUptime
}
func shouldLogOutUser() -> Bool {
if BuildSettings.logOutUserWhenPINFailuresExceeded && pinCodePreferences.numberOfPinFailures >= pinCodePreferences.maxAllowedNumberOfPinFailures {
return true
}
if BuildSettings.logOutUserWhenBiometricsFailuresExceeded && pinCodePreferences.numberOfBiometricsFailures >= pinCodePreferences.maxAllowedNumberOfBiometricsFailures {
return true
}
return false
}
}

View file

@ -72,6 +72,9 @@ import UIKit
var scrollBarStyle: UIScrollView.IndicatorStyle { get }
var keyboardAppearance: UIKeyboardAppearance { get }
@available(iOS 12.0, *)
var userInterfaceStyle: UIUserInterfaceStyle { get }
// MARK: - Colors not defined in the design palette

View file

@ -115,6 +115,8 @@ NSString *const kThemeServiceDidChangeThemeNotification = @"kThemeServiceDidChan
// Observe "Invert Colours" settings changes (available since iOS 11)
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(accessibilityInvertColorsStatusDidChange) name:UIAccessibilityInvertColorsStatusDidChangeNotification object:nil];
}
[self reEvaluateTheme];
}
return self;
}

View file

@ -71,6 +71,11 @@ class DarkTheme: NSObject, Theme {
var statusBarStyle: UIStatusBarStyle = .lightContent
var scrollBarStyle: UIScrollView.IndicatorStyle = .white
var keyboardAppearance: UIKeyboardAppearance = .dark
@available(iOS 12.0, *)
var userInterfaceStyle: UIUserInterfaceStyle {
return .dark
}
var placeholderTextColor: UIColor = UIColor(rgb: 0xA1B2D1) // Use secondary text color
var selectedBackgroundColor: UIColor = UIColor(rgb: 0x040506)

View file

@ -77,6 +77,11 @@ class DefaultTheme: NSObject, Theme {
}
var scrollBarStyle: UIScrollView.IndicatorStyle = .default
var keyboardAppearance: UIKeyboardAppearance = .light
@available(iOS 12.0, *)
var userInterfaceStyle: UIUserInterfaceStyle {
return .light
}
var placeholderTextColor: UIColor = UIColor(rgb: 0x8F97A3) // Use secondary text color

View file

@ -0,0 +1,109 @@
/*
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 Intents
/// The AppCoordinator is responsible of screen navigation and data injection at root application level. It decides if authentication or home screen should be shown and inject data needed for these flows, it changes the navigation stack on deep link, displays global warning.
/// This class should avoid to contain too many data management code not related to screen navigation logic. For example `MXSession` or push notification management should be handled in dedicated classes and report only navigation changes to the AppCoordinator.
final class AppCoordinator: NSObject, AppCoordinatorType {
// MARK: - Constants
// MARK: - Properties
// MARK: Private
private let rootRouter: RootRouterType
// swiftlint:disable weak_delegate
private let legacyAppDelegate: LegacyAppDelegate = AppDelegate.theDelegate()
// swiftlint:enable weak_delegate
private weak var splitViewCoordinator: SplitViewCoordinatorType?
// TODO: Use a dedicated class to handle Matrix sessions
/// Main user Matrix session
private var mainSession: MXSession? {
return MXKAccountManager.shared().activeAccounts.first?.mxSession
}
// MARK: Public
var childCoordinators: [Coordinator] = []
// MARK: - Setup
init(router: RootRouterType) {
self.rootRouter = router
}
// MARK: - Public methods
func start() {
self.showSplitView(session: self.mainSession)
}
// MARK: - Private methods
private func showAuthentication() {
// TODO: Implement
}
private func showLoading() {
// TODO: Implement
}
private func showPinCode() {
// TODO: Implement
}
private func showSplitView(session: MXSession?) {
let splitViewCoordinator = SplitViewCoordinator(router: self.rootRouter, session: session)
splitViewCoordinator.delegate = self
splitViewCoordinator.start()
self.add(childCoordinator: splitViewCoordinator)
self.splitViewCoordinator = splitViewCoordinator
}
private func checkAppVersion() {
// TODO: Implement
}
private func showError(_ error: Error) {
// FIXME: Present an error on coordinator.toPresentable()
self.legacyAppDelegate.showError(asAlert: error)
}
}
// MARK: - LegacyAppDelegateDelegate
extension AppCoordinator: LegacyAppDelegateDelegate {
func legacyAppDelegate(_ legacyAppDelegate: LegacyAppDelegate!, wantsToPopToHomeViewControllerAnimated animated: Bool, completion: (() -> Void)!) {
self.splitViewCoordinator?.popToHome(animated: animated, completion: completion)
}
func legacyAppDelegateRestoreEmptyDetailsViewController(_ legacyAppDelegate: LegacyAppDelegate!) {
self.splitViewCoordinator?.restorePlaceholderDetails()
}
}
// MARK: - SplitViewCoordinatorDelegate
extension AppCoordinator: SplitViewCoordinatorDelegate {
func splitViewCoordinatorDidCompleteAuthentication(_ coordinator: SplitViewCoordinatorType) {
self.legacyAppDelegate.authenticationDidComplete()
}
}

View file

@ -0,0 +1,21 @@
/*
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
/// `AppCoordinatorType` is a protocol describing a Coordinator that handles application navigation flow.
protocol AppCoordinatorType: Coordinator {
}

View file

@ -21,9 +21,12 @@ import PushKit
class AppDelegate: UIResponder, UIApplicationDelegate {
// MARK: - Properties
// MARK: Private
private var appCoordinator: AppCoordinatorType!
private var rootRouter: RootRouterType!
private var legacyAppDelegate: LegacyAppDelegate {
return AppDelegate.theDelegate()
}
@ -54,6 +57,19 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
// Setup window
let window = UIWindow(frame: UIScreen.main.bounds)
self.window = window
// Create AppCoordinator
self.rootRouter = RootRouter(window: window)
let appCoordinator = AppCoordinator(router: self.rootRouter)
appCoordinator.start()
self.legacyAppDelegate.delegate = appCoordinator
self.appCoordinator = appCoordinator
// Call legacy AppDelegate
self.legacyAppDelegate.window = window
self.legacyAppDelegate.application(application, didFinishLaunchingWithOptions: launchOptions)

View file

@ -28,7 +28,7 @@
#import "UniversalLink.h"
@protocol Configurable;
@protocol LegacyAppDelegateDelegate;
#pragma mark - Notifications
/**
@ -56,6 +56,8 @@ extern NSString *const AppDelegateUniversalLinkDidChangeNotification;
void (^_completionHandler)(UIBackgroundFetchResult);
}
@property (weak, nonatomic) id<LegacyAppDelegateDelegate> delegate;
/**
Application main view controller
*/
@ -176,6 +178,8 @@ extern NSString *const AppDelegateUniversalLinkDidChangeNotification;
- (void)configureCallManagerIfRequiredForSession:(MXSession *)mxSession;
- (void)authenticationDidComplete;
#pragma mark - Matrix Accounts handling
- (void)selectMatrixAccount:(void (^)(MXKAccount *selectedAccount))onSelection;
@ -234,3 +238,10 @@ extern NSString *const AppDelegateUniversalLinkDidChangeNotification;
- (void)checkAppVersion;
@end
@protocol LegacyAppDelegateDelegate <NSObject>
- (void)legacyAppDelegate:(LegacyAppDelegate*)legacyAppDelegate wantsToPopToHomeViewControllerAnimated:(BOOL)animated completion:(void (^)(void))completion;
- (void)legacyAppDelegateRestoreEmptyDetailsViewController:(LegacyAppDelegate*)legacyAppDelegate;
@end

View file

@ -89,7 +89,7 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUniversalLinkDidChangeNotification";
@interface LegacyAppDelegate () <GDPRConsentViewControllerDelegate, KeyVerificationCoordinatorBridgePresenterDelegate, ServiceTermsModalCoordinatorBridgePresenterDelegate, PushNotificationServiceDelegate, SetPinCoordinatorBridgePresenterDelegate, MasterTabBarControllerDelegate>
@interface LegacyAppDelegate () <GDPRConsentViewControllerDelegate, KeyVerificationCoordinatorBridgePresenterDelegate, ServiceTermsModalCoordinatorBridgePresenterDelegate, PushNotificationServiceDelegate, SetPinCoordinatorBridgePresenterDelegate>
{
/**
Reachability observer
@ -176,11 +176,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
*/
BOOL isErrorNotificationSuspended;
/**
Completion block called when [self popToHomeViewControllerAnimated:] has been
completed.
*/
void (^popToHomeViewControllerCompletion)(void);
/**
The listeners to call events.
@ -375,27 +370,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
}
}
- (UINavigationController*)secondaryNavigationController
{
UIViewController* rootViewController = self.window.rootViewController;
if ([rootViewController isKindOfClass:[UISplitViewController class]])
{
UISplitViewController *splitViewController = (UISplitViewController *)rootViewController;
if (splitViewController.viewControllers.count == 2)
{
UIViewController *secondViewController = [splitViewController.viewControllers lastObject];
if ([secondViewController isKindOfClass:[UINavigationController class]])
{
return (UINavigationController*)secondViewController;
}
}
}
return nil;
}
#pragma mark - UIApplicationDelegate
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(nullable NSDictionary *)launchOptions
@ -466,28 +440,10 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
// To simplify navigation into the app, we retrieve here the main navigation controller and the tab bar controller.
UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
splitViewController.delegate = self;
_masterNavigationController = splitViewController.viewControllers[0];
_masterTabBarController = _masterNavigationController.viewControllers.firstObject;
// Force the background color of the fake view controller displayed when there is no details.
UINavigationController *secondNavController = self.secondaryNavigationController;
if (secondNavController)
{
[ThemeService.shared.theme applyStyleOnNavigationBar:secondNavController.navigationBar];
secondNavController.topViewController.view.backgroundColor = ThemeService.shared.theme.backgroundColor;
}
// on IOS 8 iPad devices, force to display the primary and the secondary viewcontroller
// to avoid empty room View Controller in portrait orientation
// else, the user cannot select a room
// shouldHideViewController delegate method is also implemented
if ([(NSString*)[UIDevice currentDevice].model hasPrefix:@"iPad"])
{
splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible;
}
// Sanity check
NSAssert(_masterTabBarController, @"Something wrong in Main.storyboard");
@ -572,7 +528,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
wrongBackupVersionAlert = nil;
}
if ([self.localAuthenticationService isProtectionSet])
if ([self.localAuthenticationService isProtectionSet] && ![BiometricsAuthenticationPresenter isPresenting])
{
if (self.setPinCoordinatorBridgePresenter)
{
@ -584,11 +540,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
self.setPinCoordinatorBridgePresenter.delegate = self;
[self.setPinCoordinatorBridgePresenter presentIn:self.window];
}
else
{
[self.setPinCoordinatorBridgePresenter dismiss];
self.setPinCoordinatorBridgePresenter = nil;
}
}
- (void)applicationDidEnterBackground:(UIApplication *)application
@ -775,7 +726,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
[application keyWindow].accessibilityIgnoresInvertColors = YES;
}
[self handleLaunchAnimation];
[self handleAppState];
}
- (void)applicationWillTerminate:(UIApplication *)application
@ -938,32 +889,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
- (void)restoreEmptyDetailsViewController
{
UIViewController* rootViewController = self.window.rootViewController;
if ([rootViewController isKindOfClass:[UISplitViewController class]])
{
UISplitViewController *splitViewController = (UISplitViewController *)rootViewController;
// Be sure that the primary is then visible too.
if (splitViewController.displayMode == UISplitViewControllerDisplayModePrimaryHidden)
{
splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible;
}
if (splitViewController.viewControllers.count == 2)
{
UIViewController *mainViewController = splitViewController.viewControllers[0];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
UIViewController *emptyDetailsViewController = [storyboard instantiateViewControllerWithIdentifier:@"EmptyDetailsViewControllerStoryboardId"];
emptyDetailsViewController.view.backgroundColor = ThemeService.shared.theme.backgroundColor;
splitViewController.viewControllers = @[mainViewController, emptyDetailsViewController];
}
}
// Release the current selected item (room/contact/group...).
[_masterTabBarController releaseSelectedItem];
[self.delegate legacyAppDelegateRestoreEmptyDetailsViewController:self];
}
- (UIAlertController*)showErrorAsAlert:(NSError*)error
@ -1136,61 +1062,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
- (void)popToHomeViewControllerAnimated:(BOOL)animated completion:(void (^)(void))completion
{
UINavigationController *secondNavController = self.secondaryNavigationController;
if (secondNavController)
{
[secondNavController popToRootViewControllerAnimated:animated];
}
// Force back to the main screen if this is not the one that is displayed
if (_masterTabBarController && _masterTabBarController != _masterNavigationController.visibleViewController)
{
// Listen to the masterNavigationController changes
// We need to be sure that masterTabBarController is back to the screen
popToHomeViewControllerCompletion = completion;
_masterNavigationController.delegate = self;
[_masterNavigationController popToViewController:_masterTabBarController animated:animated];
}
else
{
// Select the Home tab
_masterTabBarController.selectedIndex = TABBAR_HOME_INDEX;
if (completion)
{
completion();
}
}
}
#pragma mark - UINavigationController delegate
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if (viewController == _masterTabBarController)
{
_masterNavigationController.delegate = nil;
// For unknown reason, the navigation bar is not restored correctly by [popToViewController:animated:]
// when a ViewController has hidden it (see MXKAttachmentsViewController).
// Patch: restore navigation bar by default here.
_masterNavigationController.navigationBarHidden = NO;
// Release the current selected item (room/contact/...).
[_masterTabBarController releaseSelectedItem];
if (popToHomeViewControllerCompletion)
{
void (^popToHomeViewControllerCompletion2)(void) = popToHomeViewControllerCompletion;
popToHomeViewControllerCompletion = nil;
// Dispatch the completion in order to let navigation stack refresh itself.
dispatch_async(dispatch_get_main_queue(), ^{
popToHomeViewControllerCompletion2();
});
}
}
[self.delegate legacyAppDelegate:self wantsToPopToHomeViewControllerAnimated:animated completion:completion];
}
#pragma mark - Crash handling
@ -1911,17 +1783,8 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
{
[self removeMatrixSession:mxSession];
}
else if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive)
{
if (mxSession.state == MXSessionStateRunning)
{
// Check if we need to display a key share dialog
[self checkPendingRoomKeyRequests];
[self checkPendingIncomingKeyVerificationsInSession:mxSession];
}
}
[self handleLaunchAnimation];
[self handleAppState];
}];
// Register an observer in order to handle new account
@ -2096,12 +1959,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
// Do the one time check on device id
[self checkDeviceId:mxSession];
// Enable listening of incoming key share requests
[self enableRoomKeyRequestObserver:mxSession];
// Enable listening of incoming key verification requests
[self enableIncomingKeyVerificationObserver:mxSession];
}
}
@ -2435,7 +2292,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
}];
}
- (void)handleLaunchAnimation
- (void)handleAppState
{
MXSession *mainSession = self.mxSessions.firstObject;
@ -2445,11 +2302,10 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
if (_masterTabBarController.authenticationInProgress)
{
NSLog(@"[AppDelegate] handleLaunchAnimation: Authentication still in progress");
NSLog(@"[AppDelegate] handleAppState: Authentication still in progress");
// Wait for the return of masterTabBarControllerDidCompleteAuthentication
isLaunching = YES;
_masterTabBarController.masterVCDelegate = self;
isLaunching = YES;
}
else
{
@ -2470,38 +2326,92 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
}
}
NSLog(@"[AppDelegate] handleAppState: isLaunching: %@", isLaunching ? @"YES" : @"NO");
if (isLaunching)
{
NSLog(@"[AppDelegate] handleLaunchAnimation: LaunchLoadingView");
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
if (!launchAnimationContainerView && window)
{
LaunchLoadingView *launchLoadingView = [LaunchLoadingView instantiate];
launchLoadingView.frame = window.bounds;
[launchLoadingView updateWithTheme:ThemeService.shared.theme];
launchLoadingView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[window addSubview:launchLoadingView];
launchAnimationContainerView = launchLoadingView;
launchAnimationStart = [NSDate date];
}
NSLog(@"[AppDelegate] handleAppState: LaunchLoadingView");
[self showLaunchAnimation];
return;
}
else
[self hideLaunchAnimation];
if (self.setPinCoordinatorBridgePresenter)
{
NSLog(@"[AppDelegate] handleLaunchAnimation: isLaunching: NO");
NSLog(@"[AppDelegate] handleAppState: PIN code is presented. Do not go further");
return;
}
if (mainSession.crypto.crossSigning)
{
NSLog(@"[AppDelegate] handleAppState: crossSigning.state: %@", @(mainSession.crypto.crossSigning.state));
switch (mainSession.crypto.crossSigning.state)
{
case MXCrossSigningStateCrossSigningExists:
NSLog(@"[AppDelegate] handleAppState: presentVerifyCurrentSessionAlertIfNeededWithSession");
[_masterTabBarController presentVerifyCurrentSessionAlertIfNeededWithSession:mainSession];
break;
case MXCrossSigningStateCanCrossSign:
NSLog(@"[AppDelegate] handleAppState: presentReviewUnverifiedSessionsAlertIfNeededWithSession");
[_masterTabBarController presentReviewUnverifiedSessionsAlertIfNeededWithSession:mainSession];
break;
default:
break;
}
}
// TODO: We should wait that cross-signing screens are done before going further but it seems fine. Those screens
// protect each other.
// This is the time to check existing requests
NSLog(@"[AppDelegate] handleAppState: Check pending verification requests");
[self checkPendingRoomKeyRequests];
[self checkPendingIncomingKeyVerificationsInSession:mainSession];
// TODO: When we will have an application state, we will do all of this in a dedicated initialisation state
// For the moment, reuse an existing boolean to avoid register things several times
if (!incomingKeyVerificationObserver)
{
NSLog(@"[AppDelegate] handleAppState: Set up observers for the crypto module");
// Enable listening of incoming key share requests
[self enableRoomKeyRequestObserver:mainSession];
// Enable listening of incoming key verification requests
[self enableIncomingKeyVerificationObserver:mainSession];
}
}
}
- (void)showLaunchAnimation
{
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
if (!launchAnimationContainerView && window)
{
NSLog(@"[AppDelegate] showLaunchAnimation");
LaunchLoadingView *launchLoadingView = [LaunchLoadingView instantiate];
launchLoadingView.frame = window.bounds;
[launchLoadingView updateWithTheme:ThemeService.shared.theme];
launchLoadingView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[window addSubview:launchLoadingView];
launchAnimationContainerView = launchLoadingView;
launchAnimationStart = [NSDate date];
}
}
- (void)hideLaunchAnimation
{
if (launchAnimationContainerView)
{
NSTimeInterval duration = [[NSDate date] timeIntervalSinceDate:launchAnimationStart];
NSLog(@"[AppDelegate] LaunchAnimation was shown for %.3fms", duration * 1000);
NSLog(@"[AppDelegate] hideLaunchAnimation: LaunchAnimation was shown for %.3fms", duration * 1000);
// Track it on our analytics
[[Analytics sharedInstance] trackLaunchScreenDisplayDuration:duration];
@ -2621,6 +2531,11 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
}
}
- (void)authenticationDidComplete
{
[self handleAppState];
}
#pragma mark -
/**
@ -3613,50 +3528,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
[rootController.view setNeedsLayout];
}
#pragma mark - SplitViewController delegate
- (nullable UIViewController *)splitViewController:(UISplitViewController *)splitViewController separateSecondaryViewControllerFromPrimaryViewController:(UIViewController *)primaryViewController
{
// Return the top view controller of the master navigation controller, if it is a navigation controller itself.
UIViewController *topViewController = _masterNavigationController.topViewController;
if ([topViewController isKindOfClass:UINavigationController.class])
{
return topViewController;
}
// Else return the default empty details view controller from the storyboard.
// Be sure that the primary is then visible too.
if (splitViewController.displayMode == UISplitViewControllerDisplayModePrimaryHidden)
{
splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible;
}
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
UIViewController *emptyDetailsViewController = [storyboard instantiateViewControllerWithIdentifier:@"EmptyDetailsViewControllerStoryboardId"];
emptyDetailsViewController.view.backgroundColor = ThemeService.shared.theme.backgroundColor;
return emptyDetailsViewController;
}
- (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController
{
if (!self.masterTabBarController.currentRoomViewController && !self.masterTabBarController.currentContactDetailViewController && !self.masterTabBarController.currentGroupDetailViewController)
{
// Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
return YES;
}
else
{
return NO;
}
}
- (BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController:(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation
{
// oniPad devices, force to display the primary and the secondary viewcontroller
// to avoid empty room View Controller in portrait orientation
// else, the user cannot select a room
return NO;
}
#pragma mark - Status Bar Tap handling
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
@ -4703,18 +4574,19 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
[self afterAppUnlockedByPin:[UIApplication sharedApplication]];
}
- (void)setPinCoordinatorBridgePresenterDelegateDidCompleteWithReset:(SetPinCoordinatorBridgePresenter *)coordinatorBridgePresenter
- (void)setPinCoordinatorBridgePresenterDelegateDidCompleteWithReset:(SetPinCoordinatorBridgePresenter *)coordinatorBridgePresenter dueToTooManyErrors:(BOOL)dueToTooManyErrors
{
[coordinatorBridgePresenter dismiss];
self.setPinCoordinatorBridgePresenter = nil;
[self logoutWithConfirmation:NO completion:nil];
}
#pragma mark - MasterTabBarControllerDelegate
- (void)masterTabBarControllerDidCompleteAuthentication:(MasterTabBarController *)masterTabBarController
{
[self handleLaunchAnimation];
if (dueToTooManyErrors)
{
[self showAlertWithTitle:nil message:NSLocalizedStringFromTable(@"pin_protection_kick_user_alert_message", @"Vector", nil)];
[self logoutWithConfirmation:NO completion:nil];
}
else
{
[coordinatorBridgePresenter dismiss];
self.setPinCoordinatorBridgePresenter = nil;
[self logoutWithConfirmation:NO completion:nil];
}
}
@end

View file

@ -926,7 +926,19 @@
{
loginCredentials = credentials;
SetPinCoordinatorBridgePresenter *presenter = [[SetPinCoordinatorBridgePresenter alloc] initWithSession:nil viewMode:SetPinCoordinatorViewModeSetPin];
SetPinCoordinatorViewMode viewMode = SetPinCoordinatorViewModeSetPin;
switch (self.authType) {
case MXKAuthenticationTypeLogin:
viewMode = SetPinCoordinatorViewModeSetPinAfterLogin;
break;
case MXKAuthenticationTypeRegister:
viewMode = SetPinCoordinatorViewModeSetPinAfterRegister;
break;
default:
break;
}
SetPinCoordinatorBridgePresenter *presenter = [[SetPinCoordinatorBridgePresenter alloc] initWithSession:nil viewMode:viewMode];
presenter.delegate = self;
[presenter presentFrom:self animated:YES];
self.setPinCoordinatorBridgePresenter = presenter;

View file

@ -44,9 +44,22 @@ final class CloseButton: UIButton, Themable {
// MARK: - Life cycle
override func awakeFromNib() {
super.awakeFromNib()
init() {
super.init(frame: .zero)
setup()
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setup()
}
private func setup() {
self.backgroundColor = UIColor.clear
self.setImage(Asset.Images.closeButton.image, for: .normal)
self.setupCircleView()
@ -65,6 +78,12 @@ final class CloseButton: UIButton, Themable {
private func setupCircleView() {
// sanity check
if circleBackgroundView != nil {
// already set up
return
}
let rect = CGRect(x: 0, y: 0, width: CircleBackgroundConstants.height, height: CircleBackgroundConstants.height)
let view = UIView(frame: rect)
view.translatesAutoresizingMaskIntoConstraints = false

View file

@ -41,12 +41,18 @@ final class Section: NSObject {
addRow(Row.row(withTag: tag))
}
func addRows(withCount count: Int) {
for i in 0..<count {
addRow(withTag: i)
}
}
func indexOfRow(withTag tag: Int) -> Int? {
return rows.firstIndex(where: { $0.tag == tag })
}
var hasAnyRows: Bool {
return rows.count > 0
return rows.isEmpty == false
}
}

View file

@ -999,10 +999,21 @@
__weak typeof(self) weakSelf = self;
NSString *title, *message;
if ([self.mainSession roomWithRoomId:currentRoomId].isDirect)
{
title = NSLocalizedStringFromTable(@"room_participants_leave_prompt_title_for_dm", @"Vector", nil);
message = NSLocalizedStringFromTable(@"room_participants_leave_prompt_msg_for_dm", @"Vector", nil);
}
else
{
title = NSLocalizedStringFromTable(@"room_participants_leave_prompt_title", @"Vector", nil);
message = NSLocalizedStringFromTable(@"room_participants_leave_prompt_msg", @"Vector", nil);
}
// confirm leave
NSString *promptMessage = NSLocalizedStringFromTable(@"room_participants_leave_prompt_msg", @"Vector", nil);
currentAlert = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"room_participants_leave_prompt_title", @"Vector", nil)
message:promptMessage
currentAlert = [UIAlertController alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
[currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"]

View file

@ -17,11 +17,11 @@
import Foundation
import Reusable
protocol TableViewHeaderFooterViewDelegate: UITextViewDelegate {
protocol TextViewTableViewHeaderFooterViewDelegate: UITextViewDelegate {
}
class TableViewHeaderFooterView: UITableViewHeaderFooterView {
class TextViewTableViewHeaderFooterView: UITableViewHeaderFooterView {
// MARK - Private
private var _textView: UITextView?
@ -33,7 +33,7 @@ class TableViewHeaderFooterView: UITableViewHeaderFooterView {
// MARK - Public
weak var delegate: TableViewHeaderFooterViewDelegate?
weak var delegate: TextViewTableViewHeaderFooterViewDelegate?
var textViewInsets: UIEdgeInsets = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16) {
didSet {
@ -89,9 +89,9 @@ class TableViewHeaderFooterView: UITableViewHeaderFooterView {
}
extension TableViewHeaderFooterView: Reusable { }
extension TextViewTableViewHeaderFooterView: Reusable { }
extension TableViewHeaderFooterView: Themable {
extension TextViewTableViewHeaderFooterView: Themable {
func update(theme: Theme) {
contentView.backgroundColor = theme.headerBackgroundColor
@ -102,7 +102,7 @@ extension TableViewHeaderFooterView: Themable {
}
extension TableViewHeaderFooterView: UITextViewDelegate {
extension TextViewTableViewHeaderFooterView: UITextViewDelegate {
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
return delegate?.textView?(textView, shouldInteractWith: URL, in: characterRange, interaction: interaction) ?? (interaction == .invokeDefaultAction)

View file

@ -96,7 +96,7 @@ class PlaceholderedTextView: UITextView {
NotificationCenter.default.addObserver(self, selector: #selector(textViewTextChanged(_:)), name: UITextView.textDidChangeNotification, object: self)
kvoLineFragmentPadding = observe(\.textContainer.lineFragmentPadding, options: [.new]) { [weak self] (_, change) in
guard let self = self else { return }
let newValue = change.newValue ?? 0
let newValue = change.newValue ?? 0
self.placeholderTextView.textContainer.lineFragmentPadding = newValue
}
}

View file

@ -22,6 +22,7 @@
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="jO2-1T-e01">
<rect key="frame" x="0.0" y="0.0" width="60" height="60"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</imageView>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="capture_avatar" translatesAutoresizingMaskIntoConstraints="NO" id="DmM-HO-d5u">
<rect key="frame" x="36" y="36" width="24" height="24"/>
@ -37,7 +38,7 @@
</connections>
</button>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="jO2-1T-e01" firstAttribute="top" secondItem="cxa-zY-I2z" secondAttribute="top" id="4vV-IL-HBT"/>
<constraint firstItem="jO2-1T-e01" firstAttribute="leading" secondItem="cxa-zY-I2z" secondAttribute="leading" id="EHU-dt-Wct"/>

View file

@ -254,7 +254,7 @@ final class EnterNewRoomDetailsViewController: UIViewController {
mainTableView.register(cellType: MXKTableViewCellWithTextView.self)
mainTableView.register(cellType: TextFieldTableViewCell.self)
mainTableView.register(cellType: TextViewTableViewCell.self)
mainTableView.register(headerFooterViewType: TableViewHeaderFooterView.self)
mainTableView.register(headerFooterViewType: TextViewTableViewHeaderFooterView.self)
mainTableView.sectionHeaderHeight = UITableView.automaticDimension
mainTableView.estimatedSectionHeaderHeight = 50
mainTableView.sectionFooterHeight = UITableView.automaticDimension
@ -412,7 +412,7 @@ extension EnterNewRoomDetailsViewController: UITableViewDelegate {
return nil
}
let view: TableViewHeaderFooterView? = tableView.dequeueReusableHeaderFooterView()
let view: TextViewTableViewHeaderFooterView? = tableView.dequeueReusableHeaderFooterView()
view?.textView.text = header
view?.textView.font = .systemFont(ofSize: 13)
@ -427,7 +427,7 @@ extension EnterNewRoomDetailsViewController: UITableViewDelegate {
return nil
}
let view: TableViewHeaderFooterView? = tableView.dequeueReusableHeaderFooterView()
let view: TextViewTableViewHeaderFooterView? = tableView.dequeueReusableHeaderFooterView()
view?.textView.text = footer
view?.textView.font = .systemFont(ofSize: 13)

View file

@ -29,6 +29,7 @@ final class KeyVerificationCoordinator: KeyVerificationCoordinatorType {
private let session: MXSession
private let verificationFlow: KeyVerificationFlow
private let verificationKind: KeyVerificationKind
private weak var completeSecurityCoordinator: KeyVerificationSelfVerifyWaitCoordinatorType?
private var otherUserId: String {
@ -133,7 +134,9 @@ final class KeyVerificationCoordinator: KeyVerificationCoordinatorType {
case .incomingSASTransaction(let incomingSASTransaction):
rootCoordinator = self.createDataLoadingScreenCoordinator(otherUserId: incomingSASTransaction.otherUserId, otherDeviceId: incomingSASTransaction.otherDeviceId)
case .completeSecurity(let isNewSignIn):
rootCoordinator = self.createCompleteSecurityCoordinator(isNewSignIn: isNewSignIn)
let coordinator = self.createCompleteSecurityCoordinator(isNewSignIn: isNewSignIn)
self.completeSecurityCoordinator = coordinator
rootCoordinator = coordinator
}
rootCoordinator.start()
@ -162,6 +165,14 @@ final class KeyVerificationCoordinator: KeyVerificationCoordinatorType {
}
private func didCancel() {
// In the case of the complete security flow, come back to the root screen if any child flow
// like device verification has been cancelled
if self.completeSecurityCoordinator != nil && childCoordinators.count > 1 {
NSLog("[KeyVerificationCoordinator] didCancel: popToRootModule")
self.navigationRouter.popToRootModule(animated: true)
return
}
self.delegate?.keyVerificationCoordinatorDidCancel(self)
}
@ -179,9 +190,6 @@ final class KeyVerificationCoordinator: KeyVerificationCoordinatorType {
coordinator.start()
self.add(childCoordinator: coordinator)
self.navigationRouter.setRootModule(coordinator) { [weak self] in
self?.remove(childCoordinator: coordinator)
}
}
private func createSelfVerificationCoordinator(otherDeviceId: String) -> KeyVerificationSelfVerifyStartCoordinator {
@ -445,10 +453,12 @@ extension KeyVerificationCoordinator: KeyVerificationScanConfirmationCoordinator
extension KeyVerificationCoordinator: SecretsRecoveryCoordinatorDelegate {
func secretsRecoveryCoordinatorDidRecover(_ coordinator: SecretsRecoveryCoordinatorType) {
self.remove(childCoordinator: coordinator)
self.showVerified(animated: true)
}
func secretsRecoveryCoordinatorDidCancel(_ coordinator: SecretsRecoveryCoordinatorType) {
self.remove(childCoordinator: coordinator)
self.didCancel()
}
}

View file

@ -140,7 +140,6 @@ final class KeyVerificationSelfVerifyWaitViewModel: KeyVerificationSelfVerifyWai
return
}
self.unregisterKeyVerificationManagerNewRequestNotification()
self.coordinatorDelegate?.keyVerificationSelfVerifyWaitViewModel(self, didAcceptKeyVerificationRequest: keyVerificationRequest)
}, failure: { [weak self] (error) in
@ -200,8 +199,6 @@ final class KeyVerificationSelfVerifyWaitViewModel: KeyVerificationSelfVerifyWai
private func sasTransactionDidStateChange(_ transaction: MXIncomingSASTransaction) {
switch transaction.state {
case MXSASTransactionStateIncomingShowAccept:
// Stop listening for incoming request
self.unregisterKeyVerificationManagerNewRequestNotification()
transaction.accept()
case MXSASTransactionStateShowSAS:
self.unregisterTransactionDidStateChangeNotification()

View file

@ -92,4 +92,10 @@
}
}
- (void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion
{
BOOL animated = flag && !self.presentingViewController.presentingViewController;
[super dismissViewControllerAnimated:animated completion:completion];
}
@end

View file

@ -112,9 +112,14 @@ final class RoomCreationEventsModalViewModel: RoomCreationEventsModalViewModelTy
events.append(contentsOf: bubbleData.events)
var nextBubbleData = bubbleData.nextCollapsableCellData
while nextBubbleData != nil {
// swiftlint:disable force_unwrapping
events.append(contentsOf: nextBubbleData!.events)
// swiftlint:enable force_unwrapping
nextBubbleData = nextBubbleData?.nextCollapsableCellData
}
// remove room create event from the list, as EW and ElA do. This will also avoid duplication of "%@ joined" messages for direct rooms.
events.removeAll(where: { $0.eventType == .roomCreate })
}
// MARK: - Public

View file

@ -860,10 +860,20 @@
case UserEncryptionTrustLevelNotVerified:
case UserEncryptionTrustLevelNoCrossSigning:
case UserEncryptionTrustLevelTrusted:
[encryptionInformation appendString:NSLocalizedStringFromTable(@"room_participants_security_information_room_encrypted", @"Vector", nil)];
{
NSString *info = (self.mxRoom.isDirect) ?
NSLocalizedStringFromTable(@"room_participants_security_information_room_encrypted_for_dm", @"Vector", nil) :
NSLocalizedStringFromTable(@"room_participants_security_information_room_encrypted", @"Vector", nil);
[encryptionInformation appendString:info];
}
break;
case UserEncryptionTrustLevelNone:
[encryptionInformation appendString:NSLocalizedStringFromTable(@"room_participants_security_information_room_not_encrypted", @"Vector", nil)];
{
NSString *info = (self.mxRoom.isDirect) ?
NSLocalizedStringFromTable(@"room_participants_security_information_room_not_encrypted_for_dm", @"Vector", nil) :
NSLocalizedStringFromTable(@"room_participants_security_information_room_not_encrypted", @"Vector", nil);
[encryptionInformation appendString:info];
}
break;
case UserEncryptionTrustLevelUnknown:
[encryptionInformation appendString:NSLocalizedStringFromTable(@"room_participants_security_information_loading", @"Vector", nil)];

View file

@ -120,7 +120,14 @@
self.navigationItem.title = NSLocalizedStringFromTable(@"room_participants_title", @"Vector", nil);
_searchBarView.placeholder = NSLocalizedStringFromTable(@"room_participants_filter_room_members", @"Vector", nil);
if (self.mxRoom.isDirect)
{
_searchBarView.placeholder = NSLocalizedStringFromTable(@"room_participants_filter_room_members_for_dm", @"Vector", nil);
}
else
{
_searchBarView.placeholder = NSLocalizedStringFromTable(@"room_participants_filter_room_members", @"Vector", nil);
}
_searchBarView.returnKeyType = UIReturnKeyDone;
_searchBarView.autocapitalizationType = UITextAutocapitalizationTypeNone;
@ -378,6 +385,15 @@
if (self.mxRoom)
{
self.searchBarHeader.hidden = NO;
if (self.mxRoom.isDirect)
{
self.searchBarView.placeholder = NSLocalizedStringFromTable(@"room_participants_filter_room_members_for_dm", @"Vector", nil);
}
else
{
self.searchBarView.placeholder = NSLocalizedStringFromTable(@"room_participants_filter_room_members", @"Vector", nil);
}
// Update the current matrix session.
[self addMatrixSession:self.mxRoom.mxSession];
@ -1393,8 +1409,21 @@
{
// Leave ?
MXWeakify(self);
currentAlert = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"room_participants_leave_prompt_title", @"Vector", nil)
message:NSLocalizedStringFromTable(@"room_participants_leave_prompt_msg", @"Vector", nil)
NSString *title, *message;
if (self.mxRoom.isDirect)
{
title = NSLocalizedStringFromTable(@"room_participants_leave_prompt_title_for_dm", @"Vector", nil);
message = NSLocalizedStringFromTable(@"room_participants_leave_prompt_msg_for_dm", @"Vector", nil);
}
else
{
title = NSLocalizedStringFromTable(@"room_participants_leave_prompt_title", @"Vector", nil);
message = NSLocalizedStringFromTable(@"room_participants_leave_prompt_msg", @"Vector", nil);
}
currentAlert = [UIAlertController alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
[currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"]

View file

@ -0,0 +1,136 @@
// File created from FlowTemplate
// $ createRootCoordinator.sh Room2 RoomInfo RoomInfoList
/*
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
@objcMembers
final class RoomInfoCoordinator: NSObject, RoomInfoCoordinatorType {
// MARK: - Properties
// MARK: Private
private let navigationRouter: NavigationRouterType
private let session: MXSession
private let room: MXRoom
private lazy var segmentedViewController: SegmentedViewController = {
let controller = SegmentedViewController()
let participants = RoomParticipantsViewController()
participants.finalizeInit()
participants.enableMention = true
participants.mxRoom = self.room
participants.delegate = self
let files = RoomFilesViewController()
files.finalizeInit()
MXKRoomDataSource.load(withRoomId: self.room.roomId, andMatrixSession: self.session) { (dataSource) in
guard let dataSource = dataSource as? MXKRoomDataSource else { return }
dataSource.filterMessagesWithURL = true
dataSource.finalizeInitialization()
files.hasRoomDataSourceOwnership = true
files.displayRoom(dataSource)
}
let settings = RoomSettingsViewController()
settings.finalizeInit()
settings.initWith(self.session, andRoomId: self.room.roomId)
if self.room.isDirect {
controller.title = VectorL10n.roomDetailsTitleForDm
} else {
controller.title = VectorL10n.roomDetailsTitle
}
controller.initWithTitles([
VectorL10n.roomDetailsPeople,
VectorL10n.roomDetailsFiles,
VectorL10n.roomDetailsSettings
], viewControllers: [
participants,
files,
settings
], defaultSelected: 0)
controller.addMatrixSession(self.session)
_ = controller.view
return controller
}()
// MARK: Public
// Must be used only internally
var childCoordinators: [Coordinator] = []
weak var delegate: RoomInfoCoordinatorDelegate?
// MARK: - Setup
init(session: MXSession, room: MXRoom) {
self.navigationRouter = NavigationRouter(navigationController: RiotNavigationController())
self.session = session
self.room = room
}
// MARK: - Public methods
func start() {
let rootCoordinator = self.createRoomInfoListCoordinator()
rootCoordinator.start()
self.add(childCoordinator: rootCoordinator)
self.navigationRouter.setRootModule(rootCoordinator)
}
func toPresentable() -> UIViewController {
return self.navigationRouter.toPresentable()
}
// MARK: - Private methods
private func createRoomInfoListCoordinator() -> RoomInfoListCoordinator {
let coordinator = RoomInfoListCoordinator(session: self.session, room: room)
coordinator.delegate = self
return coordinator
}
}
// MARK: - RoomInfoListCoordinatorDelegate
extension RoomInfoCoordinator: RoomInfoListCoordinatorDelegate {
func roomInfoListCoordinator(_ coordinator: RoomInfoListCoordinatorType, wantsToNavigateTo target: RoomInfoListTarget) {
segmentedViewController.selectedIndex = target.rawValue
navigationRouter.push(segmentedViewController, animated: true, popCompletion: nil)
}
func roomInfoListCoordinatorDidCancel(_ coordinator: RoomInfoListCoordinatorType) {
self.delegate?.roomInfoCoordinatorDidComplete(self)
}
}
extension RoomInfoCoordinator: RoomParticipantsViewControllerDelegate {
func roomParticipantsViewController(_ roomParticipantsViewController: RoomParticipantsViewController!, mention member: MXRoomMember!) {
}
}

View file

@ -0,0 +1,99 @@
// File created from FlowTemplate
// $ createRootCoordinator.sh Room2 RoomInfo RoomInfoList
/*
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
@objc protocol RoomInfoCoordinatorBridgePresenterDelegate {
func roomInfoCoordinatorBridgePresenterDelegateDidComplete(_ coordinatorBridgePresenter: RoomInfoCoordinatorBridgePresenter)
}
/// RoomInfoCoordinatorBridgePresenter enables to start RoomInfoCoordinator from a view controller.
/// This bridge is used while waiting for global usage of coordinator pattern.
@objcMembers
final class RoomInfoCoordinatorBridgePresenter: NSObject {
// MARK: - Properties
// MARK: Private
private let session: MXSession
private let room: MXRoom
private var coordinator: RoomInfoCoordinator?
// MARK: Public
weak var delegate: RoomInfoCoordinatorBridgePresenterDelegate?
// MARK: - Setup
init(session: MXSession, room: MXRoom) {
self.session = session
self.room = room
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, animated: Bool) {
let roomInfoCoordinator = RoomInfoCoordinator(session: self.session, room: room)
roomInfoCoordinator.delegate = self
let presentable = roomInfoCoordinator.toPresentable()
presentable.presentationController?.delegate = self
viewController.present(presentable, animated: animated, completion: nil)
roomInfoCoordinator.start()
self.coordinator = roomInfoCoordinator
}
func dismiss(animated: Bool, completion: (() -> Void)?) {
guard let coordinator = self.coordinator else {
return
}
coordinator.toPresentable().dismiss(animated: animated) {
self.coordinator = nil
if let completion = completion {
completion()
}
}
}
}
// MARK: - RoomInfoCoordinatorDelegate
extension RoomInfoCoordinatorBridgePresenter: RoomInfoCoordinatorDelegate {
func roomInfoCoordinatorDidComplete(_ coordinator: RoomInfoCoordinatorType) {
self.delegate?.roomInfoCoordinatorBridgePresenterDelegateDidComplete(self)
}
}
// MARK: - UIAdaptivePresentationControllerDelegate
extension RoomInfoCoordinatorBridgePresenter: UIAdaptivePresentationControllerDelegate {
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
self.delegate?.roomInfoCoordinatorBridgePresenterDelegateDidComplete(self)
}
}

View file

@ -0,0 +1,28 @@
// File created from FlowTemplate
// $ createRootCoordinator.sh Room2 RoomInfo RoomInfoList
/*
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 RoomInfoCoordinatorDelegate: class {
func roomInfoCoordinatorDidComplete(_ coordinator: RoomInfoCoordinatorType)
}
/// `RoomInfoCoordinatorType` is a protocol describing a Coordinator that handle keybackup setup navigation flow.
protocol RoomInfoCoordinatorType: Coordinator, Presentable {
var delegate: RoomInfoCoordinatorDelegate? { get }
}

View file

@ -0,0 +1,74 @@
// File created from ScreenTemplate
// $ createScreen.sh Room2/RoomInfo RoomInfoList
/*
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 RoomInfoListCoordinator: RoomInfoListCoordinatorType {
// MARK: - Properties
// MARK: Private
private let session: MXSession
private let room: MXRoom
private var roomInfoListViewModel: RoomInfoListViewModelType
private let roomInfoListViewController: RoomInfoListViewController
// MARK: Public
// Must be used only internally
var childCoordinators: [Coordinator] = []
weak var delegate: RoomInfoListCoordinatorDelegate?
// MARK: - Setup
init(session: MXSession, room: MXRoom) {
self.session = session
self.room = room
let roomInfoListViewModel = RoomInfoListViewModel(session: self.session, room: room)
let roomInfoListViewController = RoomInfoListViewController.instantiate(with: roomInfoListViewModel)
self.roomInfoListViewModel = roomInfoListViewModel
self.roomInfoListViewController = roomInfoListViewController
}
// MARK: - Public methods
func start() {
self.roomInfoListViewModel.coordinatorDelegate = self
}
func toPresentable() -> UIViewController {
return self.roomInfoListViewController
}
}
// MARK: - RoomInfoListViewModelCoordinatorDelegate
extension RoomInfoListCoordinator: RoomInfoListViewModelCoordinatorDelegate {
func roomInfoListViewModel(_ viewModel: RoomInfoListViewModelType, wantsToNavigateTo target: RoomInfoListTarget) {
self.delegate?.roomInfoListCoordinator(self, wantsToNavigateTo: target)
}
func roomInfoListViewModelDidCancel(_ viewModel: RoomInfoListViewModelType) {
self.delegate?.roomInfoListCoordinatorDidCancel(self)
}
}

View file

@ -0,0 +1,29 @@
// File created from ScreenTemplate
// $ createScreen.sh Room2/RoomInfo RoomInfoList
/*
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 RoomInfoListCoordinatorDelegate: class {
func roomInfoListCoordinator(_ coordinator: RoomInfoListCoordinatorType, wantsToNavigateTo target: RoomInfoListTarget)
func roomInfoListCoordinatorDidCancel(_ coordinator: RoomInfoListCoordinatorType)
}
/// `RoomInfoListCoordinatorType` is a protocol describing a Coordinator that handle key backup setup passphrase navigation flow.
protocol RoomInfoListCoordinatorType: Coordinator, Presentable {
var delegate: RoomInfoListCoordinatorDelegate? { get }
}

View file

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

View file

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16096" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="V8j-Lb-PgC">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Room Info List View Controller-->
<scene sceneID="mt5-wz-YKA">
<objects>
<viewController extendedLayoutIncludesOpaqueBars="YES" automaticallyAdjustsScrollViewInsets="NO" id="V8j-Lb-PgC" customClass="RoomInfoListViewController" customModule="Riot" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="EL9-GA-lwo">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" translatesAutoresizingMaskIntoConstraints="NO" id="hlX-bE-0GF">
<rect key="frame" x="0.0" y="44" width="414" height="852"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<connections>
<outlet property="dataSource" destination="V8j-Lb-PgC" id="kn3-kz-ejx"/>
<outlet property="delegate" destination="V8j-Lb-PgC" id="k8u-1x-U3s"/>
</connections>
</tableView>
</subviews>
<color key="backgroundColor" red="0.94509803921568625" green="0.96078431372549022" blue="0.97254901960784312" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstItem="hlX-bE-0GF" firstAttribute="leading" secondItem="EL9-GA-lwo" secondAttribute="leading" id="ctc-dj-0Ld"/>
<constraint firstAttribute="trailing" secondItem="hlX-bE-0GF" secondAttribute="trailing" id="h3A-l4-f0I"/>
<constraint firstAttribute="bottom" secondItem="hlX-bE-0GF" secondAttribute="bottom" id="kRS-ik-Qkd"/>
<constraint firstItem="hlX-bE-0GF" firstAttribute="top" secondItem="bFg-jh-JZB" secondAttribute="top" id="mTZ-Fd-TBV"/>
</constraints>
<viewLayoutGuide key="safeArea" id="bFg-jh-JZB"/>
</view>
<connections>
<outlet property="mainTableView" destination="hlX-bE-0GF" id="PTk-mr-QeO"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="zK0-v6-7Wt" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-3198" y="-647"/>
</scene>
</scenes>
</document>

View file

@ -0,0 +1,385 @@
// File created from ScreenTemplate
// $ createScreen.sh Room2/RoomInfo RoomInfoList
/*
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 RoomInfoListViewController: UIViewController {
// MARK: - Constants
private enum Constants {
static let defaultStyleCellReuseIdentifier = "default"
static let tableViewSectionMinHeight: CGFloat = 8.0
}
// MARK: - Properties
// MARK: Outlets
@IBOutlet private weak var mainTableView: UITableView!
// MARK: Private
private var viewModel: RoomInfoListViewModelType!
private var theme: Theme!
private var errorPresenter: MXKErrorPresentation!
private var activityPresenter: ActivityIndicatorPresenter!
private var isRoomDirect: Bool = false
private lazy var closeButton: CloseButton = {
let button = CloseButton()
button.isHighlighted = true
button.addTarget(self, action: #selector(closeButtonTapped(_:)), for: .touchUpInside)
return button
}()
private lazy var basicInfoView: RoomInfoBasicView = {
let view = RoomInfoBasicView.loadFromNib()
view.autoresizingMask = .flexibleWidth
view.translatesAutoresizingMaskIntoConstraints = true
return view
}()
private lazy var leaveAlertController: UIAlertController = {
let title = self.isRoomDirect ? VectorL10n.roomParticipantsLeavePromptTitleForDm : VectorL10n.roomParticipantsLeavePromptTitle
let message = self.isRoomDirect ? VectorL10n.roomParticipantsLeavePromptMsgForDm : VectorL10n.roomParticipantsLeavePromptMsg
let controller = UIAlertController(title: title, message: message, preferredStyle: .alert)
controller.addAction(UIAlertAction(title: VectorL10n.cancel, style: .cancel, handler: nil))
controller.addAction(UIAlertAction(title: VectorL10n.leave, style: .default, handler: { [weak self] (action) in
guard let self = self else { return }
self.viewModel.process(viewAction: .leave)
}))
controller.mxk_setAccessibilityIdentifier("RoomSettingsVCLeaveAlert")
return controller
}()
private enum RowType {
case `default`
case destructive
}
private struct Row {
var type: RowType
var icon: UIImage?
var text: String?
var accessoryType: UITableViewCell.AccessoryType = .none
var action: (() -> Void)?
}
private struct Section {
var header: String?
var rows: [Row]
var footer: String?
}
private var sections: [Section] = [] {
didSet {
mainTableView.reloadData()
}
}
// MARK: - Setup
class func instantiate(with viewModel: RoomInfoListViewModelType) -> RoomInfoListViewController {
let viewController = StoryboardScene.RoomInfoListViewController.initialScene.instantiate()
viewController.viewModel = viewModel
viewController.theme = ThemeService.shared().theme
return viewController
}
// MARK: - Life cycle
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.setupViews()
self.activityPresenter = ActivityIndicatorPresenter()
self.errorPresenter = MXKErrorAlertPresentation()
self.registerThemeServiceDidChangeThemeNotification()
self.update(theme: self.theme)
self.viewModel.viewDelegate = self
self.viewModel.process(viewAction: .loadData)
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return self.theme.statusBarStyle
}
// MARK: - Private
private func updateSections(with viewData: RoomInfoListViewData) {
isRoomDirect = viewData.isDirect
basicInfoView.configure(withViewData: viewData.basicInfoViewData)
var tmpSections: [Section] = []
if viewData.isEncrypted {
let footer = viewData.isDirect ?
VectorL10n.roomParticipantsSecurityInformationRoomEncryptedForDm :
VectorL10n.roomParticipantsSecurityInformationRoomEncrypted
let sectionSecurity = Section(header: VectorL10n.securitySettingsTitle,
rows: [],
footer: footer)
tmpSections.append(sectionSecurity)
}
let rowSettings = Row(type: .default, icon: Asset.Images.settingsIcon.image, text: VectorL10n.roomDetailsSettings, accessoryType: .disclosureIndicator) {
self.viewModel.process(viewAction: .navigate(target: .settings))
}
let text = viewData.numberOfMembers == 1 ? VectorL10n.roomInfoListOneMember : VectorL10n.roomInfoListSeveralMembers(String(viewData.numberOfMembers))
let rowMembers = Row(type: .default, icon: Asset.Images.userIcon.image, text: text, accessoryType: .disclosureIndicator) {
self.viewModel.process(viewAction: .navigate(target: .members))
}
let rowUploads = Row(type: .default, icon: Asset.Images.scrollup.image, text: VectorL10n.roomDetailsFiles, accessoryType: .disclosureIndicator) {
self.viewModel.process(viewAction: .navigate(target: .uploads))
}
let sectionSettings = Section(header: VectorL10n.roomInfoListSectionOther,
rows: [rowSettings,
rowMembers,
rowUploads],
footer: nil)
let leaveTitle = viewData.isDirect ?
VectorL10n.roomParticipantsLeavePromptTitleForDm :
VectorL10n.roomParticipantsLeavePromptTitle
let rowLeave = Row(type: .destructive, icon: Asset.Images.roomActionLeave.image, text: leaveTitle, accessoryType: .none) {
self.present(self.leaveAlertController, animated: true, completion: nil)
}
let sectionLeave = Section(header: nil,
rows: [rowLeave],
footer: nil)
tmpSections.append(sectionSettings)
tmpSections.append(sectionLeave)
sections = tmpSections
}
private func update(theme: Theme) {
self.theme = theme
self.view.backgroundColor = theme.headerBackgroundColor
self.mainTableView.backgroundColor = theme.headerBackgroundColor
if let navigationBar = self.navigationController?.navigationBar {
theme.applyStyle(onNavigationBar: navigationBar)
}
closeButton.update(theme: theme)
basicInfoView.update(theme: theme)
mainTableView.reloadData()
}
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() {
self.navigationItem.rightBarButtonItem = MXKBarButtonItem(customView: closeButton)
self.title = ""
mainTableView.register(headerFooterViewType: TextViewTableViewHeaderFooterView.self)
mainTableView.sectionHeaderHeight = UITableView.automaticDimension
mainTableView.estimatedSectionHeaderHeight = 50
mainTableView.sectionFooterHeight = UITableView.automaticDimension
mainTableView.estimatedSectionFooterHeight = 50
mainTableView.rowHeight = UITableView.automaticDimension
mainTableView.tableHeaderView = basicInfoView
}
private func render(viewState: RoomInfoListViewState) {
switch viewState {
case .loading:
self.renderLoading()
case .loaded(let viewData):
self.renderLoaded(viewData: viewData)
case .error(let error):
self.render(error: error)
}
}
private func renderLoading() {
self.activityPresenter.presentActivityIndicator(on: self.view, animated: true)
}
private func renderLoaded(viewData: RoomInfoListViewData) {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
self.updateSections(with: viewData)
}
private func render(error: Error) {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: nil)
}
// MARK: - Actions
@objc private func closeButtonTapped(_ sender: Any) {
self.viewModel.process(viewAction: .cancel)
}
}
// MARK: - UITableViewDataSource
extension RoomInfoListViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sections[section].rows.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let row = sections[indexPath.section].rows[indexPath.row]
switch row.type {
case .default, .destructive:
var cell: UITableViewCell! = tableView.dequeueReusableCell(withIdentifier: Constants.defaultStyleCellReuseIdentifier)
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: Constants.defaultStyleCellReuseIdentifier)
}
if let icon = row.icon {
if row.type == .default {
cell.imageView?.image = MXKTools.resize(icon, to: CGSize(width: 20, height: 20))?.vc_tintedImage(usingColor: theme.textSecondaryColor)
} else if row.type == .destructive {
cell.imageView?.image = MXKTools.resize(icon, to: CGSize(width: 20, height: 20))?.vc_tintedImage(usingColor: theme.noticeColor)
}
}
cell.textLabel?.font = .systemFont(ofSize: 17)
cell.detailTextLabel?.font = .systemFont(ofSize: 16)
cell.textLabel?.text = row.text
if row.accessoryType == .checkmark {
cell.accessoryView = UIImageView(image: Asset.Images.checkmark.image)
} else {
cell.accessoryView = nil
cell.accessoryType = row.accessoryType
}
if row.type == .default {
cell.textLabel?.textColor = theme.textPrimaryColor
cell.detailTextLabel?.textColor = theme.textSecondaryColor
} else if row.type == .destructive {
cell.textLabel?.textColor = theme.noticeColor
cell.detailTextLabel?.textColor = theme.noticeSecondaryColor
}
cell.backgroundColor = theme.backgroundColor
cell.contentView.backgroundColor = .clear
cell.tintColor = theme.tintColor
return cell
}
}
}
// MARK: - UITableViewDelegate
extension RoomInfoListViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.backgroundColor = theme.backgroundColor
cell.selectedBackgroundView = UIView()
cell.selectedBackgroundView?.backgroundColor = theme.selectedBackgroundColor
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section].header
}
func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
return sections[section].footer
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
guard let header = sections[section].header else {
return nil
}
let view: TextViewTableViewHeaderFooterView? = tableView.dequeueReusableHeaderFooterView()
view?.textView.text = header
view?.textView.font = .systemFont(ofSize: 13)
view?.textViewInsets = UIEdgeInsets(top: 16, left: 16, bottom: 8, right: 16)
view?.update(theme: theme)
return view
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
guard let footer = sections[section].footer else {
return nil
}
let view: TextViewTableViewHeaderFooterView? = tableView.dequeueReusableHeaderFooterView()
view?.textView.text = footer
view?.textView.font = .systemFont(ofSize: 13)
view?.update(theme: theme)
return view
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let row = sections[indexPath.section].rows[indexPath.row]
row.action?()
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if sections[section].header == nil {
return Constants.tableViewSectionMinHeight
}
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
if sections[section].footer == nil {
return Constants.tableViewSectionMinHeight
}
return UITableView.automaticDimension
}
}
// MARK: - RoomInfoListViewModelViewDelegate
extension RoomInfoListViewController: RoomInfoListViewModelViewDelegate {
func roomInfoListViewModel(_ viewModel: RoomInfoListViewModelType, didUpdateViewState viewSate: RoomInfoListViewState) {
self.render(viewState: viewSate)
}
}

View file

@ -0,0 +1,27 @@
// File created from ScreenTemplate
// $ createScreen.sh Room2/RoomInfo RoomInfoList
/*
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
/// View data object to represent view
struct RoomInfoListViewData {
let numberOfMembers: Int
let isEncrypted: Bool
let isDirect: Bool
let basicInfoViewData: RoomInfoBasicViewData
}

View file

@ -0,0 +1,120 @@
// File created from ScreenTemplate
// $ createScreen.sh Room2/RoomInfo RoomInfoList
/*
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 RoomInfoListViewModel: NSObject, RoomInfoListViewModelType {
// MARK: - Properties
// MARK: Private
private let session: MXSession
private let room: MXRoom
// MARK: Public
weak var viewDelegate: RoomInfoListViewModelViewDelegate?
weak var coordinatorDelegate: RoomInfoListViewModelCoordinatorDelegate?
private var viewData: RoomInfoListViewData {
let encryptionImage = EncryptionTrustLevelBadgeImageHelper.roomBadgeImage(for: room.summary.roomEncryptionTrustLevel())
let basicInfoViewData = RoomInfoBasicViewData(avatarUrl: room.summary.avatar,
mediaManager: session.mediaManager,
roomId: room.roomId,
roomDisplayName: room.summary.displayname,
mainRoomAlias: room.summary.aliases?.first,
roomTopic: room.summary.topic,
encryptionImage: encryptionImage)
return RoomInfoListViewData(numberOfMembers: Int(room.summary.membersCount.joined),
isEncrypted: room.summary.isEncrypted,
isDirect: room.isDirect,
basicInfoViewData: basicInfoViewData)
}
// MARK: - Setup
init(session: MXSession, room: MXRoom) {
self.session = session
self.room = room
super.init()
startObservingSummaryChanges()
}
deinit {
stopObservingSummaryChanges()
}
// MARK: - Public
func process(viewAction: RoomInfoListViewAction) {
switch viewAction {
case .loadData:
self.loadData()
case .navigate(let target):
self.navigate(to: target)
case .leave:
self.leave()
case .cancel:
self.coordinatorDelegate?.roomInfoListViewModelDidCancel(self)
}
}
// MARK: - Private
private func startObservingSummaryChanges() {
NotificationCenter.default.addObserver(self, selector: #selector(roomSummaryUpdated(_:)), name: .mxRoomSummaryDidChange, object: room.summary)
}
private func stopObservingSummaryChanges() {
NotificationCenter.default.removeObserver(self, name: .mxRoomSummaryDidChange, object: nil)
}
@objc private func roomSummaryUpdated(_ notification: Notification) {
// force update view
self.update(viewState: .loaded(viewData: viewData))
}
private func loadData() {
self.update(viewState: .loaded(viewData: viewData))
}
private func navigate(to target: RoomInfoListTarget) {
self.coordinatorDelegate?.roomInfoListViewModel(self, wantsToNavigateTo: target)
}
private func leave() {
self.stopObservingSummaryChanges()
self.update(viewState: .loading)
self.room.leave { (response) in
switch response {
case .success:
self.coordinatorDelegate?.roomInfoListViewModelDidCancel(self)
case .failure(let error):
self.startObservingSummaryChanges()
self.update(viewState: .error(error))
}
}
}
private func update(viewState: RoomInfoListViewState) {
self.viewDelegate?.roomInfoListViewModel(self, didUpdateViewState: viewState)
}
}

View file

@ -0,0 +1,37 @@
// File created from ScreenTemplate
// $ createScreen.sh Room2/RoomInfo RoomInfoList
/*
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 RoomInfoListViewModelViewDelegate: class {
func roomInfoListViewModel(_ viewModel: RoomInfoListViewModelType, didUpdateViewState viewSate: RoomInfoListViewState)
}
protocol RoomInfoListViewModelCoordinatorDelegate: class {
func roomInfoListViewModelDidCancel(_ viewModel: RoomInfoListViewModelType)
func roomInfoListViewModel(_ viewModel: RoomInfoListViewModelType, wantsToNavigateTo target: RoomInfoListTarget)
}
/// Protocol describing the view model used by `RoomInfoListViewController`
protocol RoomInfoListViewModelType {
var viewDelegate: RoomInfoListViewModelViewDelegate? { get set }
var coordinatorDelegate: RoomInfoListViewModelCoordinatorDelegate? { get set }
func process(viewAction: RoomInfoListViewAction)
}

View file

@ -0,0 +1,26 @@
// File created from ScreenTemplate
// $ createScreen.sh Room2/RoomInfo RoomInfoList
/*
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
/// RoomInfoListViewController view state
enum RoomInfoListViewState {
case loading
case loaded(viewData: RoomInfoListViewData)
case error(Error)
}

View file

@ -0,0 +1,81 @@
//
// 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
import Reusable
class RoomInfoBasicView: UIView {
@IBOutlet private weak var mainStackView: UIStackView!
@IBOutlet private weak var avatarImageView: MXKImageView!
@IBOutlet private weak var shadowView: UIView! {
didSet {
let shadowPath = UIBezierPath(roundedRect: shadowView.bounds, cornerRadius: 0)
let layer = CALayer()
layer.shadowPath = shadowPath.cgPath
layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.12).cgColor
layer.shadowOpacity = 1
layer.shadowRadius = 25
layer.shadowOffset = CGSize(width: 0, height: 4)
layer.bounds = shadowView.bounds
layer.position = shadowView.center
shadowView.layer.addSublayer(layer)
}
}
@IBOutlet private weak var badgeImageView: UIImageView!
@IBOutlet private weak var roomNameLabel: UILabel!
@IBOutlet private weak var roomAddressLabel: UILabel!
@IBOutlet private weak var roomTopicLabel: UILabel!
func configure(withViewData viewData: RoomInfoBasicViewData) {
let avatarImage = AvatarGenerator.generateAvatar(forMatrixItem: viewData.roomId, withDisplayName: viewData.roomDisplayName)
if let avatarUrl = viewData.avatarUrl {
avatarImageView.enableInMemoryCache = true
avatarImageView.setImageURI(avatarUrl,
withType: nil,
andImageOrientation: .up,
toFitViewSize: avatarImageView.frame.size,
with: MXThumbnailingMethodCrop,
previewImage: avatarImage,
mediaManager: viewData.mediaManager)
} else {
avatarImageView.image = avatarImage
}
badgeImageView.image = viewData.encryptionImage
roomNameLabel.text = viewData.roomDisplayName
roomAddressLabel.text = viewData.mainRoomAlias
roomAddressLabel.isHidden = roomAddressLabel.text?.isEmpty ?? true
roomTopicLabel.text = viewData.roomTopic
roomTopicLabel.isHidden = roomTopicLabel.text?.isEmpty ?? true
}
}
extension RoomInfoBasicView: NibLoadable {}
extension RoomInfoBasicView: Themable {
func update(theme: Theme) {
backgroundColor = theme.headerBackgroundColor
roomNameLabel.textColor = theme.textPrimaryColor
roomAddressLabel.textColor = theme.textSecondaryColor
roomTopicLabel.textColor = theme.textSecondaryColor
}
}

View file

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16096" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="RoomInfoBasicView" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="414" height="183"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" verticalCompressionResistancePriority="751" axis="vertical" distribution="equalSpacing" alignment="center" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="xmU-kN-zva">
<rect key="frame" x="0.0" y="0.0" width="414" height="183"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Tgy-Pv-0Gz">
<rect key="frame" x="87" y="0.0" width="240" height="1"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="5Hy-Jn-UrY"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="uhx-GK-2je">
<rect key="frame" x="167" y="11" width="80" height="80"/>
<subviews>
<view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="6tV-Ha-dWM" customClass="MXKImageView">
<rect key="frame" x="0.0" y="0.0" width="80" height="80"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
<integer key="value" value="40"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="szu-r5-TIX">
<rect key="frame" x="0.0" y="0.0" width="80" height="80"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</view>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="CPx-Kp-81p">
<rect key="frame" x="56" y="56" width="24" height="24"/>
<constraints>
<constraint firstAttribute="height" constant="24" id="i5v-oL-sm2"/>
<constraint firstAttribute="width" constant="24" id="xNQ-sH-hA2"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="CPx-Kp-81p" secondAttribute="trailing" id="6RG-lL-haL"/>
<constraint firstItem="6tV-Ha-dWM" firstAttribute="top" secondItem="uhx-GK-2je" secondAttribute="top" id="BoZ-qJ-yLh"/>
<constraint firstItem="6tV-Ha-dWM" firstAttribute="leading" secondItem="uhx-GK-2je" secondAttribute="leading" id="Cct-TF-2Cj"/>
<constraint firstItem="szu-r5-TIX" firstAttribute="leading" secondItem="uhx-GK-2je" secondAttribute="leading" id="D8c-8Q-pof"/>
<constraint firstItem="szu-r5-TIX" firstAttribute="top" secondItem="uhx-GK-2je" secondAttribute="top" id="GI9-rA-rhp"/>
<constraint firstAttribute="bottom" secondItem="6tV-Ha-dWM" secondAttribute="bottom" id="ISw-Ft-Kvj"/>
<constraint firstAttribute="width" constant="80" id="Wak-DS-q4j"/>
<constraint firstAttribute="height" constant="80" id="am1-8t-b28"/>
<constraint firstAttribute="bottom" secondItem="szu-r5-TIX" secondAttribute="bottom" id="mqD-nK-e6K"/>
<constraint firstAttribute="bottom" secondItem="CPx-Kp-81p" secondAttribute="bottom" id="vLA-vu-R2o"/>
<constraint firstAttribute="trailing" secondItem="6tV-Ha-dWM" secondAttribute="trailing" id="wCp-YW-duP"/>
<constraint firstAttribute="trailing" secondItem="szu-r5-TIX" secondAttribute="trailing" id="xqQ-Ue-Ldl"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" text="Label" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ekk-PI-fnh">
<rect key="frame" x="182" y="100.5" width="50.5" height="24"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="20"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" text="Label" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Yjw-ez-u4W">
<rect key="frame" x="187.5" y="134.5" width="39.5" height="19.5"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" text="Label" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="3" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Qyh-eC-KBG">
<rect key="frame" x="187.5" y="163.5" width="39.5" height="19.5"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="xmU-kN-zva" secondAttribute="trailing" id="JAT-xr-qng"/>
<constraint firstAttribute="bottom" secondItem="xmU-kN-zva" secondAttribute="bottom" id="Zen-46-8Ks"/>
<constraint firstItem="xmU-kN-zva" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="ciH-WD-B1a"/>
<constraint firstItem="xmU-kN-zva" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="qbE-Xx-IK9"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="avatarImageView" destination="6tV-Ha-dWM" id="HPF-WW-KeR"/>
<outlet property="badgeImageView" destination="CPx-Kp-81p" id="YTo-hB-enE"/>
<outlet property="mainStackView" destination="xmU-kN-zva" id="Hsg-6X-ATq"/>
<outlet property="roomAddressLabel" destination="Yjw-ez-u4W" id="R1L-VC-qHV"/>
<outlet property="roomNameLabel" destination="ekk-PI-fnh" id="prM-OG-suY"/>
<outlet property="roomTopicLabel" destination="Qyh-eC-KBG" id="qN7-ic-y6n"/>
<outlet property="shadowView" destination="szu-r5-TIX" id="LDd-uy-FAG"/>
</connections>
<point key="canvasLocation" x="243.47826086956525" y="-273.54910714285711"/>
</view>
</objects>
</document>

View file

@ -0,0 +1,29 @@
//
// 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 MatrixKit
struct RoomInfoBasicViewData {
let avatarUrl: String?
let mediaManager: MXMediaManager?
let roomId: String
let roomDisplayName: String?
let mainRoomAlias: String?
let roomTopic: String?
let encryptionImage: UIImage?
}

View file

@ -29,10 +29,6 @@
@interface RoomViewController : MXKRoomViewController
// The expanded header
@property (weak, nonatomic) IBOutlet UIView *expandedHeaderContainer;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *expandedHeaderContainerHeightConstraint;
// The preview header
@property (weak, nonatomic) IBOutlet UIView *previewHeaderContainer;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *previewHeaderContainerHeightConstraint;
@ -46,14 +42,6 @@
@property (weak, nonatomic) IBOutlet UIButton *resetReadMarkerButton;
@property (weak, nonatomic) IBOutlet UIView *jumpToLastUnreadBannerSeparatorView;
/**
Force the display of the expanded header.
The default value is NO: this expanded header is hidden on new instantiated RoomViewController object.
When this property is YES, the expanded header is forced each time the view controller appears.
*/
@property (nonatomic) BOOL showExpandedHeader;
/**
Preview data for a room invitation received by email, or a link to a room.
*/

View file

@ -126,10 +126,8 @@
@interface RoomViewController () <UISearchBarDelegate, UIGestureRecognizerDelegate, UIScrollViewAccessibilityDelegate, RoomTitleViewTapGestureDelegate, RoomParticipantsViewControllerDelegate, MXKRoomMemberDetailsViewControllerDelegate, ContactsTableViewControllerDelegate, MXServerNoticesDelegate, RoomContextualMenuViewControllerDelegate,
ReactionsMenuViewModelCoordinatorDelegate, EditHistoryCoordinatorBridgePresenterDelegate, MXKDocumentPickerPresenterDelegate, EmojiPickerCoordinatorBridgePresenterDelegate,
ReactionHistoryCoordinatorBridgePresenterDelegate, CameraPresenterDelegate, MediaPickerCoordinatorBridgePresenterDelegate,
RoomDataSourceDelegate, RoomCreationModalCoordinatorBridgePresenterDelegate>
RoomDataSourceDelegate, RoomCreationModalCoordinatorBridgePresenterDelegate, RoomInfoCoordinatorBridgePresenterDelegate>
{
// The expanded header
ExpandedRoomTitleView *expandedHeader;
// The preview header
PreviewRoomTitleView *previewHeader;
@ -234,6 +232,7 @@
@property (nonatomic, strong) MediaPickerCoordinatorBridgePresenter *mediaPickerPresenter;
@property (nonatomic, strong) RoomMessageURLParser *roomMessageURLParser;
@property (nonatomic, strong) RoomCreationModalCoordinatorBridgePresenter *roomCreationModalCoordinatorBridgePresenter;
@property (nonatomic, strong) RoomInfoCoordinatorBridgePresenter *roomInfoCoordinatorBridgePresenter;
@end
@ -297,7 +296,6 @@
self.rageShakeManager = [RageShakeManager sharedManager];
formattedBodyParser = [FormattedBodyParser new];
_showExpandedHeader = NO;
_showMissedDiscussionsBadge = YES;
@ -369,44 +367,6 @@
[self.bubblesTableView registerClass:RoomCreationCollapsedBubbleCell.class forCellReuseIdentifier:RoomCreationCollapsedBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomCreationWithPaginationCollapsedBubbleCell.class forCellReuseIdentifier:RoomCreationWithPaginationCollapsedBubbleCell.defaultReuseIdentifier];
// Prepare expanded header
expandedHeader = [ExpandedRoomTitleView roomTitleView];
expandedHeader.delegate = self;
expandedHeader.tapGestureDelegate = self;
expandedHeader.translatesAutoresizingMaskIntoConstraints = NO;
[self.expandedHeaderContainer addSubview:expandedHeader];
// Force expanded header in full width
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:expandedHeader
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.expandedHeaderContainer
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0];
NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:expandedHeader
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.expandedHeaderContainer
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:0];
NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:expandedHeader
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.expandedHeaderContainer
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:0];
[NSLayoutConstraint activateConstraints:@[leftConstraint, rightConstraint, topConstraint]];
UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(onSwipeGesture:)];
[swipe setNumberOfTouchesRequired:1];
[swipe setDirection:UISwipeGestureRecognizerDirectionUp];
[self.expandedHeaderContainer addGestureRecognizer:swipe];
// Replace the default input toolbar view.
// Note: this operation will force the layout of subviews. That is why cell view classes must be registered before.
[self updateRoomInputToolbarViewClassIfNeeded];
@ -470,7 +430,7 @@
}
// Keep navigation bar transparent in some cases
if (!self.expandedHeaderContainer.hidden || !self.previewHeaderContainer.hidden)
if (!self.previewHeaderContainer.hidden)
{
self.navigationController.navigationBar.translucent = YES;
mainNavigationController.navigationBar.translucent = YES;
@ -486,7 +446,6 @@
self.jumpToLastUnreadLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
self.jumpToLastUnreadBannerSeparatorView.backgroundColor = ThemeService.shared.theme.lineBreakColor;
self.expandedHeaderContainer.backgroundColor = ThemeService.shared.theme.baseColor;
self.previewHeaderContainer.backgroundColor = ThemeService.shared.theme.headerBackgroundColor;
missedDiscussionsBadgeLabel.textColor = ThemeService.shared.theme.baseTextPrimaryColor;
@ -539,11 +498,6 @@
[self listenTombstoneEventNotifications];
[self listenMXSessionStateChangeNotifications];
if (self.showExpandedHeader)
{
[self showExpandedHeader:YES];
}
// Observe kAppDelegateDidTapStatusBarNotification.
kAppDelegateDidTapStatusBarNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kAppDelegateDidTapStatusBarNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
@ -573,8 +527,7 @@
}
}
// Hide expanded/preview header to restore navigation bar settings
[self showExpandedHeader:NO];
// Hide preview header to restore navigation bar settings
[self showPreviewHeader:NO];
if (kAppDelegateDidTapStatusBarNotificationObserver)
@ -670,12 +623,7 @@
// Check here whether a subview has been added or removed
if (encryptionInfoView)
{
if (encryptionInfoView.superview)
{
// Hide the potential expanded header when a subview is added.
self.showExpandedHeader = NO;
}
else
if (!encryptionInfoView.superview)
{
// Reset
encryptionInfoView = nil;
@ -687,51 +635,15 @@
if (eventDetailsView)
{
if (eventDetailsView.superview)
{
// Hide the potential expanded header when a subview is added.
self.showExpandedHeader = NO;
}
else
if (!eventDetailsView.superview)
{
// Reset
eventDetailsView = nil;
}
}
// Check whether the expanded header is visible
if (self.expandedHeaderContainer.isHidden == NO)
{
// Adjust the expanded header height by taking into account the actual position of the room avatar
// This position depends automatically on the screen orientation.
if ([self.titleView isKindOfClass:[RoomAvatarTitleView class]])
{
RoomAvatarTitleView *avatarTitleView = (RoomAvatarTitleView*)self.titleView;
CGPoint roomAvatarOriginInTitleView = avatarTitleView.roomAvatarMask.frame.origin;
CGPoint roomAvatarActualPosition = [avatarTitleView convertPoint:roomAvatarOriginInTitleView toView:self.view];
CGFloat avatarHeaderHeight = roomAvatarActualPosition.y + expandedHeader.roomAvatar.frame.size.height;
if (expandedHeader.roomAvatarHeaderBackgroundHeightConstraint.constant != avatarHeaderHeight)
{
expandedHeader.roomAvatarHeaderBackgroundHeightConstraint.constant = avatarHeaderHeight;
// Force the layout of expandedHeader to update the position of 'bottomBorderView' which
// is used to define the actual height of the expanded header container.
[expandedHeader layoutIfNeeded];
}
}
self.edgesForExtendedLayout = UIRectEdgeAll;
// Adjust the top constraint of the bubbles table
CGRect frame = expandedHeader.bottomBorderView.frame;
self.expandedHeaderContainerHeightConstraint.constant = frame.origin.y + frame.size.height;
self.bubblesTableViewTopConstraint.constant = self.expandedHeaderContainerHeightConstraint.constant - self.bubblesTableView.mxk_adjustedContentInset.top;
self.jumpToLastUnreadBannerContainerTopConstraint.constant = self.expandedHeaderContainerHeightConstraint.constant;
}
// Check whether the preview header is visible
else if (previewHeader)
if (previewHeader)
{
if (previewHeader.mainHeaderContainer.isHidden)
{
@ -780,9 +692,6 @@
// If we don't hide the header, the navigation bar is in a wrong state after rotation. FIXME: Find a way to keep visible the header on rotation.
if ([GBDeviceInfo deviceInfo].family == GBDeviceFamilyiPad || [GBDeviceInfo deviceInfo].displayInfo.display >= GBDeviceDisplay5p5Inch)
{
// Hide the expanded header (if any) on device rotation
[self showExpandedHeader:NO];
// Hide the preview header (if any) before rotating (It will be restored by `refreshRoomTitle` call if this is still a room preview).
[self showPreviewHeader:NO];
@ -1023,15 +932,6 @@
if (self.roomDataSource)
{
// Force expanded header refresh if it is visible
if (self.expandedHeaderContainer.isHidden == NO)
{
expandedHeader.mxRoom = self.roomDataSource.room;
// Force the layout of subviews (some constraints may have been updated)
[self forceLayoutRefresh];
}
// Restore tool bar view and room activities view if none
if (!self.inputToolbarView)
{
@ -1053,8 +953,6 @@
- (void)leaveRoomOnEvent:(MXEvent*)event
{
[self showExpandedHeader:NO];
// Force a simple title view initialised with the current room before leaving actually the room.
[self setRoomTitleViewClass:SimpleRoomTitleView.class];
self.titleView.editable = NO;
@ -1192,17 +1090,6 @@
{
[super setKeyboardHeight:keyboardHeight];
if (keyboardHeight)
{
// Hide the potential expanded header when keyboard appears.
// Dispatch this operation to prevent flickering in navigation bar.
dispatch_async(dispatch_get_main_queue(), ^{
[self showExpandedHeader:NO];
});
}
// Make the activity indicator follow the keyboard
// At runtime, this creates a smooth animation
CGPoint activityIndicatorCenter = self.activityIndicator.center;
@ -1328,7 +1215,7 @@
[self removeMXSessionStateChangeNotificationsListener];
[self removeServerNoticesListener];
if (previewHeader || (self.expandedHeaderContainer.isHidden == NO))
if (previewHeader)
{
// Here [destroy] is called before [viewWillDisappear:]
NSLog(@"[RoomVC] destroyed whereas it is still visible");
@ -1340,9 +1227,6 @@
self.previewHeaderContainer.hidden = YES;
}
[expandedHeader removeFromSuperview];
expandedHeader = nil;
roomPreviewData = nil;
missedDiscussionsBarButtonCustomView = nil;
@ -1357,12 +1241,6 @@
#pragma mark -
- (void)setShowExpandedHeader:(BOOL)showExpandedHeader
{
_showExpandedHeader = showExpandedHeader;
[self showExpandedHeader:showExpandedHeader];
}
- (void)setShowMissedDiscussionsBadge:(BOOL)showMissedDiscussionsBadge
{
_showMissedDiscussionsBadge = showMissedDiscussionsBadge;
@ -1508,19 +1386,8 @@
}
// Do not change title view class here if the expanded header is visible.
if (self.expandedHeaderContainer.hidden)
{
[self setRoomTitleViewClass:RoomTitleView.class];
((RoomTitleView*)self.titleView).tapGestureDelegate = self;
}
else
{
// Force expanded header refresh
expandedHeader.mxRoom = self.roomDataSource.room;
// Force the layout of subviews (some constraints may have been updated)
[self forceLayoutRefresh];
}
[self setRoomTitleViewClass:RoomTitleView.class];
((RoomTitleView*)self.titleView).tapGestureDelegate = self;
}
else
{
@ -1627,13 +1494,7 @@
{
UIView *view = swipeGestureRecognizer.view;
if (view == self.expandedHeaderContainer)
{
// Hide the expanded header when user swipes upward on expanded header.
// We reset here the property 'showExpandedHeader'. Then the header is not expanded automatically on viewWillAppear.
self.showExpandedHeader = NO;
}
else if (view == self.activitiesView)
if (view == self.activitiesView)
{
// Dismiss the keyboard when user swipes down on activities view.
[self.inputToolbarView dismissKeyboard];
@ -1673,14 +1534,6 @@
}
}
- (void)updateExpandedHeaderEncryptionDecoration
{
if (self->expandedHeader)
{
self->expandedHeader.roomAvatarBadgeImageView.image = self.roomEncryptionBadgeImage;
}
}
- (void)updateTitleViewEncryptionDecoration
{
if (![self.titleView isKindOfClass:[RoomTitleView class]])
@ -1763,97 +1616,6 @@
[self.roomCreationModalCoordinatorBridgePresenter presentFrom:self animated:YES];
}
#pragma mark - Hide/Show expanded header
- (void)showExpandedHeader:(BOOL)isVisible
{
if (self.expandedHeaderContainer.isHidden == isVisible)
{
// Check conditions before making the expanded room header visible.
// This operation is ignored:
// - if a screen rotation is in progress.
// - if the room data source has been removed.
// - if the room data source does not manage a live timeline.
// - if the user's membership is not 'join'.
// - if the view controller is not embedded inside a split view controller yet.
// - if the encryption view is displayed
// - if the event details view is displayed
if (isVisible && (isSizeTransitionInProgress == YES || !self.roomDataSource || !self.roomDataSource.isLive || (self.roomDataSource.room.summary.membership != MXMembershipJoin) || !self.splitViewController || encryptionInfoView.superview || eventDetailsView.superview))
{
NSLog(@"[RoomVC] Show expanded header ignored");
return;
}
self.expandedHeaderContainer.hidden = !isVisible;
// Consider the main navigation controller if the current view controller is embedded inside a split view controller.
UINavigationController *mainNavigationController = self.navigationController;
if (self.splitViewController.isCollapsed && self.splitViewController.viewControllers.count)
{
mainNavigationController = self.splitViewController.viewControllers.firstObject;
}
// When the expanded header is displayed, we hide the bottom border of the navigation bar (the shadow image).
// The default shadow image is nil. When non-nil, this property represents a custom shadow image to show instead
// of the default. For a custom shadow image to be shown, a custom background image must also be set with the
// setBackgroundImage:forBarMetrics: method. If the default background image is used, then the default shadow
// image will be used regardless of the value of this property.
UIImage *shadowImage = nil;
if (isVisible)
{
[self setRoomTitleViewClass:RoomAvatarTitleView.class];
// Note the avatar title view does not define tap gesture.
expandedHeader.roomAvatar.alpha = 0.0;
expandedHeader.roomAvatarBadgeImageView.alpha = 0.0;
shadowImage = [[UIImage alloc] init];
[self updateExpandedHeaderEncryptionDecoration];
// Dismiss the keyboard when header is expanded.
[self.inputToolbarView dismissKeyboard];
}
else
{
[self setRoomTitleViewClass:RoomTitleView.class];
((RoomTitleView*)self.titleView).tapGestureDelegate = self;
}
// Force the layout of expandedHeader to update the position of 'bottomBorderView' which is used
// to define the actual height of the expandedHeader container.
[expandedHeader layoutIfNeeded];
CGRect frame = expandedHeader.bottomBorderView.frame;
self.expandedHeaderContainerHeightConstraint.constant = frame.origin.y + frame.size.height;
// Report shadow image
[mainNavigationController.navigationBar setShadowImage:shadowImage];
[mainNavigationController.navigationBar setBackgroundImage:shadowImage forBarMetrics:UIBarMetricsDefault];
mainNavigationController.navigationBar.translucent = isVisible;
self.navigationController.navigationBar.translucent = isVisible;
// Hide contextual menu if needed
[self hideContextualMenuAnimated:YES];
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseIn
animations:^{
self.bubblesTableViewTopConstraint.constant = (isVisible ? self.expandedHeaderContainerHeightConstraint.constant - self.bubblesTableView.mxk_adjustedContentInset.top : 0);
self.jumpToLastUnreadBannerContainerTopConstraint.constant = (isVisible ? self.expandedHeaderContainerHeightConstraint.constant : self.bubblesTableView.mxk_adjustedContentInset.top);
self->expandedHeader.roomAvatar.alpha = 1;
self->expandedHeader.roomAvatarBadgeImageView.alpha = 1;
// Force to render the view
[self forceLayoutRefresh];
}
completion:^(BOOL finished){
}];
}
}
#pragma mark - Hide/Show preview header
- (void)showPreviewHeader:(BOOL)isVisible
@ -3357,7 +3119,6 @@
- (void)roomDataSource:(RoomDataSource *)roomDataSource didUpdateEncryptionTrustLevel:(RoomEncryptionTrustLevel)roomEncryptionTrustLevel
{
[self updateInputToolbarEncryptionDecoration];
[self updateExpandedHeaderEncryptionDecoration];
[self updateTitleViewEncryptionDecoration];
}
@ -3419,7 +3180,14 @@
selectedRoomDetailsIndex = 0;
}
segmentedViewController.title = NSLocalizedStringFromTable(@"room_details_title", @"Vector", nil);
if (self.roomDataSource.room.isDirect)
{
segmentedViewController.title = NSLocalizedStringFromTable(@"room_details_title", @"Vector", nil);
}
else
{
segmentedViewController.title = NSLocalizedStringFromTable(@"room_details_title_for_dm", @"Vector", nil);
}
[segmentedViewController initWithTitles:titles viewControllers:viewControllers defaultSelected:selectedRoomDetailsIndex];
// Add the current session to be able to observe its state change.
@ -3840,8 +3608,6 @@
}
else if (sender == self.jumpToLastUnreadButton)
{
// Hide expanded header to restore navigation bar settings.
[self showExpandedHeader:NO];
// Dismiss potential keyboard.
[self dismissKeyboard];
@ -3946,20 +3712,6 @@
{
[super scrollViewWillBeginDragging:scrollView];
}
if (!self.expandedHeaderContainer.isHidden)
{
// Store here the position of the first touch down event
UIPanGestureRecognizer *panGestureRecognizer = scrollView.panGestureRecognizer;
if (panGestureRecognizer && panGestureRecognizer.numberOfTouches)
{
startScrollingPoint = [panGestureRecognizer locationOfTouch:0 inView:self.view];
}
else
{
startScrollingPoint = CGPointZero;
}
}
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
@ -4013,19 +3765,7 @@
- (void)onScrollViewDidEndScrolling:(UIScrollView *)scrollView
{
// Check whether the user's finger has been dragged over the expanded header.
// In that case the expanded header is collapsed
if (self.expandedHeaderContainer.isHidden == NO && (startScrollingPoint.y != 0))
{
UIPanGestureRecognizer *panGestureRecognizer = scrollView.panGestureRecognizer;
CGPoint translate = [panGestureRecognizer translationInView:self.view];
if (startScrollingPoint.y + translate.y < self.expandedHeaderContainer.frame.size.height)
{
// Hide the expanded header by reseting the property 'showExpandedHeader'. Then the header is not expanded automatically on viewWillAppear.
self.showExpandedHeader = NO;
}
}
}
#pragma mark - MXKRoomTitleViewDelegate
@ -4044,64 +3784,9 @@
if (tappedView == titleView.titleMask)
{
if (self.expandedHeaderContainer.isHidden)
{
// Expand the header
[self showExpandedHeader:YES];
}
else
{
selectedRoomSettingsField = RoomSettingsViewControllerFieldNone;
CGPoint point = [tapGestureRecognizer locationInView:self.expandedHeaderContainer];
CGRect roomNameArea = expandedHeader.displayNameTextField.frame;
roomNameArea.origin.x -= 10;
roomNameArea.origin.y -= 10;
roomNameArea.size.width += 20;
roomNameArea.size.height += 15;
if (CGRectContainsPoint(roomNameArea, point))
{
// Starting to move the local preview view
selectedRoomSettingsField = RoomSettingsViewControllerFieldName;
}
else
{
CGRect roomTopicArea = expandedHeader.roomTopic.frame;
roomTopicArea.origin.x -= 10;
roomTopicArea.size.width += 20;
roomTopicArea.size.height += 10;
if (CGRectContainsPoint(roomTopicArea, point))
{
// Starting to move the local preview view
selectedRoomSettingsField = RoomSettingsViewControllerFieldTopic;
}
else
{
CGRect roomAvatarFrame = expandedHeader.roomAvatar.frame;
if (CGRectContainsPoint(roomAvatarFrame, point))
{
// Starting to move the local preview view
selectedRoomSettingsField = RoomSettingsViewControllerFieldAvatar;
}
}
}
// Open room settings
selectedRoomDetailsIndex = 2;
[self performSegueWithIdentifier:@"showRoomDetails" sender:self];
}
}
else if (tappedView == titleView.roomDetailsMask)
{
// Open room details by selecting member list
selectedRoomDetailsIndex = 0;
[self performSegueWithIdentifier:@"showRoomDetails" sender:self];
}
else if (tappedView == titleView.addParticipantMask)
{
// Open contact picker
[self performSegueWithIdentifier:@"showContactPicker" sender:self];
self.roomInfoCoordinatorBridgePresenter = [[RoomInfoCoordinatorBridgePresenter alloc] initWithSession:self.roomDataSource.mxSession room:self.roomDataSource.room];
self.roomInfoCoordinatorBridgePresenter.delegate = self;
[self.roomInfoCoordinatorBridgePresenter presentFrom:self animated:YES];
}
else if (tappedView == previewHeader.rightButton)
{
@ -6025,4 +5710,12 @@
self.roomCreationModalCoordinatorBridgePresenter = nil;
}
#pragma mark - RoomInfoCoordinatorBridgePresenterDelegate
- (void)roomInfoCoordinatorBridgePresenterDelegateDidComplete:(RoomInfoCoordinatorBridgePresenter *)coordinatorBridgePresenter
{
[coordinatorBridgePresenter dismissWithAnimated:YES completion:nil];
self.roomInfoCoordinatorBridgePresenter = nil;
}
@end

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16096" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
@ -13,8 +13,6 @@
<outlet property="bubblesTableView" destination="BGD-sd-SQR" id="OG4-Tw-Ovt"/>
<outlet property="bubblesTableViewBottomConstraint" destination="1SD-y2-oTg" id="n8D-hT-eqt"/>
<outlet property="bubblesTableViewTopConstraint" destination="bFw-dg-qEr" id="KxM-H0-h2y"/>
<outlet property="expandedHeaderContainer" destination="uK2-9a-rZj" id="0lY-NB-cR1"/>
<outlet property="expandedHeaderContainerHeightConstraint" destination="w9z-HS-7wJ" id="6uK-Bn-TcU"/>
<outlet property="jumpToLastUnreadBannerContainer" destination="S6r-bo-jxw" id="Ady-Eh-4E0"/>
<outlet property="jumpToLastUnreadBannerContainerTopConstraint" destination="5eM-eJ-khq" id="b1J-aM-ZcT"/>
<outlet property="jumpToLastUnreadBannerSeparatorView" destination="knN-q1-QkJ" id="hHJ-c8-QfN"/>
@ -45,14 +43,6 @@
<userDefinedRuntimeAttribute type="string" keyPath="accessibilityIdentifier" value="RoomVCBubblesTableView"/>
</userDefinedRuntimeAttributes>
</tableView>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="uK2-9a-rZj" userLabel="Expanded Header Container" customClass="ExpandedRoomTitleView">
<rect key="frame" x="0.0" y="0.0" width="375" height="215"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="RoomVCExpandedHeaderContainer"/>
<constraints>
<constraint firstAttribute="height" constant="215" id="w9z-HS-7wJ"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="54r-18-K1g">
<rect key="frame" x="0.0" y="0.0" width="375" height="368"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@ -163,19 +153,16 @@
<constraint firstItem="BGD-sd-SQR" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="ECb-mP-EOG"/>
<constraint firstAttribute="trailing" secondItem="BGD-sd-SQR" secondAttribute="trailing" id="EGD-cX-OGq"/>
<constraint firstItem="gt1-EO-UVY" firstAttribute="trailing" secondItem="QpJ-1u-4ii" secondAttribute="trailing" id="L9A-P5-xeT"/>
<constraint firstItem="uK2-9a-rZj" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="La0-tN-FQS"/>
<constraint firstItem="XX4-n6-hCm" firstAttribute="leading" secondItem="QpJ-1u-4ii" secondAttribute="leading" id="Os4-cU-eQb"/>
<constraint firstItem="XX4-n6-hCm" firstAttribute="bottom" secondItem="nLd-BP-JAE" secondAttribute="top" id="QO8-nF-xys"/>
<constraint firstItem="nLd-BP-JAE" firstAttribute="leading" secondItem="QpJ-1u-4ii" secondAttribute="leading" id="T1Y-r9-bYV"/>
<constraint firstItem="XX4-n6-hCm" firstAttribute="trailing" secondItem="QpJ-1u-4ii" secondAttribute="trailing" id="Tij-mR-KZp"/>
<constraint firstItem="S6r-bo-jxw" firstAttribute="trailing" secondItem="QpJ-1u-4ii" secondAttribute="trailing" id="VVn-vW-lbm"/>
<constraint firstItem="uK2-9a-rZj" firstAttribute="top" secondItem="QpJ-1u-4ii" secondAttribute="top" id="YYB-1t-IGE"/>
<constraint firstItem="gt1-EO-UVY" firstAttribute="top" secondItem="QpJ-1u-4ii" secondAttribute="top" id="YfN-0Z-0bc"/>
<constraint firstItem="S6r-bo-jxw" firstAttribute="centerX" secondItem="BGD-sd-SQR" secondAttribute="centerX" id="a2s-5o-q2d"/>
<constraint firstItem="54r-18-K1g" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="aR5-rp-1Cp"/>
<constraint firstItem="gt1-EO-UVY" firstAttribute="bottom" secondItem="nLd-BP-JAE" secondAttribute="bottom" id="acJ-g8-R7x"/>
<constraint firstItem="BGD-sd-SQR" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="bFw-dg-qEr"/>
<constraint firstAttribute="trailing" secondItem="uK2-9a-rZj" secondAttribute="trailing" id="cWS-QJ-2qP"/>
<constraint firstAttribute="bottom" secondItem="nLd-BP-JAE" secondAttribute="bottom" id="omU-sm-3bK"/>
<constraint firstItem="nLd-BP-JAE" firstAttribute="trailing" secondItem="QpJ-1u-4ii" secondAttribute="trailing" id="pRw-S0-6WL"/>
<constraint firstAttribute="trailing" secondItem="54r-18-K1g" secondAttribute="trailing" id="wOi-Ih-yfq"/>

View file

@ -554,7 +554,14 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
}
[sectionAccess addRowWithTag:ROOM_SETTINGS_ROOM_ACCESS_DIRECTORY_VISIBILITY];
sectionAccess.headerTitle = NSLocalizedStringFromTable(@"room_details_access_section", @"Vector", nil);
if (mxRoom.isDirect)
{
sectionAccess.headerTitle = NSLocalizedStringFromTable(@"room_details_access_section_for_dm", @"Vector", nil);
}
else
{
sectionAccess.headerTitle = NSLocalizedStringFromTable(@"room_details_access_section", @"Vector", nil);
}
[tmpSections addObject:sectionAccess];
}
@ -2239,7 +2246,14 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
roomPhotoCell.mxkImageView.defaultBackgroundColor = [UIColor clearColor];
roomPhotoCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_photo", @"Vector", nil);
if (mxRoom.isDirect)
{
roomPhotoCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_photo_for_dm", @"Vector", nil);
}
else
{
roomPhotoCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_photo", @"Vector", nil);
}
roomPhotoCell.mxkLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
if (updatedItemsDict[kRoomSettingsAvatarKey])
@ -2296,7 +2310,14 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
roomNameCell.mxkTextFieldLeadingConstraint.constant = 16;
roomNameCell.mxkTextFieldTrailingConstraint.constant = 15;
roomNameCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_room_name", @"Vector", nil);
if (mxRoom.isDirect)
{
roomNameCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_room_name_for_dm", @"Vector", nil);
}
else
{
roomNameCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_room_name", @"Vector", nil);
}
roomNameCell.mxkLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
roomNameCell.accessoryType = UITableViewCellAccessoryNone;
@ -2418,7 +2439,14 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
{
MXKTableViewCellWithLabelAndSwitch *directoryToggleCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
directoryToggleCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_access_section_directory_toggle", @"Vector", nil);
if (mxRoom.isDirect)
{
directoryToggleCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_access_section_directory_toggle_for_dm", @"Vector", nil);
}
else
{
directoryToggleCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_access_section_directory_toggle", @"Vector", nil);
}
[directoryToggleCell.mxkSwitch addTarget:self action:@selector(toggleDirectoryVisibility:) forControlEvents:UIControlEventValueChanged];
@ -2482,7 +2510,14 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
}
else if (row == ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ANYONE_APART_FROM_GUEST)
{
roomAccessCell.label.text = NSLocalizedStringFromTable(@"room_details_access_section_anyone_apart_from_guest", @"Vector", nil);
if (mxRoom.isDirect)
{
roomAccessCell.label.text = NSLocalizedStringFromTable(@"room_details_access_section_anyone_apart_from_guest_for_dm", @"Vector", nil);
}
else
{
roomAccessCell.label.text = NSLocalizedStringFromTable(@"room_details_access_section_anyone_apart_from_guest", @"Vector", nil);
}
roomAccessCell.enabled = ([joinRule isEqualToString:kMXRoomJoinRulePublic] && [guestAccess isEqualToString:kMXRoomGuestAccessForbidden]);
@ -2490,7 +2525,14 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
}
else if (row == ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ANYONE)
{
roomAccessCell.label.text = NSLocalizedStringFromTable(@"room_details_access_section_anyone", @"Vector", nil);
if (mxRoom.isDirect)
{
roomAccessCell.label.text = NSLocalizedStringFromTable(@"room_details_access_section_anyone_for_dm", @"Vector", nil);
}
else
{
roomAccessCell.label.text = NSLocalizedStringFromTable(@"room_details_access_section_anyone", @"Vector", nil);
}
roomAccessCell.enabled = ([joinRule isEqualToString:kMXRoomJoinRulePublic] && [guestAccess isEqualToString:kMXRoomGuestAccessCanJoin]);
@ -2610,7 +2652,14 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
addressCell.accessoryView = nil;
addressCell.accessoryType = UITableViewCellAccessoryNone;
addressCell.selectionStyle = UITableViewCellSelectionStyleNone;
addressCell.textLabel.text = NSLocalizedStringFromTable(@"room_details_no_local_addresses", @"Vector", nil);
if (mxRoom.isDirect)
{
addressCell.textLabel.text = NSLocalizedStringFromTable(@"room_details_no_local_addresses_for_dm", @"Vector", nil);
}
else
{
addressCell.textLabel.text = NSLocalizedStringFromTable(@"room_details_no_local_addresses", @"Vector", nil);
}
cell = addressCell;
}
@ -2740,7 +2789,14 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
}
cell.textLabel.font = [UIFont systemFontOfSize:17];
cell.textLabel.text = NSLocalizedStringFromTable(@"room_details_advanced_room_id", @"Vector", nil);
if (mxRoom.isDirect)
{
cell.textLabel.text = NSLocalizedStringFromTable(@"room_details_advanced_room_id_for_dm", @"Vector", nil);
}
else
{
cell.textLabel.text = NSLocalizedStringFromTable(@"room_details_advanced_room_id", @"Vector", nil);
}
cell.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
cell.detailTextLabel.font = [UIFont systemFontOfSize:15];
@ -2801,7 +2857,14 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
cell.textLabel.font = [UIFont systemFontOfSize:17];
cell.textLabel.numberOfLines = 0;
cell.textLabel.text = NSLocalizedStringFromTable(@"room_details_advanced_e2e_encryption_enabled", @"Vector", nil);
if (mxRoom.isDirect)
{
cell.textLabel.text = NSLocalizedStringFromTable(@"room_details_advanced_e2e_encryption_enabled_for_dm", @"Vector", nil);
}
else
{
cell.textLabel.text = NSLocalizedStringFromTable(@"room_details_advanced_e2e_encryption_enabled", @"Vector", nil);
}
cell.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
@ -2828,7 +2891,14 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
cell.textLabel.font = [UIFont systemFontOfSize:17];
cell.textLabel.numberOfLines = 0;
cell.textLabel.text = NSLocalizedStringFromTable(@"room_details_advanced_e2e_encryption_disabled", @"Vector", nil);
if (mxRoom.isDirect)
{
cell.textLabel.text = NSLocalizedStringFromTable(@"room_details_advanced_e2e_encryption_disabled_for_dm", @"Vector", nil);
}
else
{
cell.textLabel.text = NSLocalizedStringFromTable(@"room_details_advanced_e2e_encryption_disabled", @"Vector", nil);
}
cell.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
@ -3377,9 +3447,20 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
[currentAlert dismissViewControllerAnimated:NO completion:nil];
NSString *title, *message;
if ([self.mainSession roomWithRoomId:self.roomId].isDirect)
{
title = NSLocalizedStringFromTable(@"room_participants_leave_prompt_title_for_dm", @"Vector", nil);
message = NSLocalizedStringFromTable(@"room_participants_leave_prompt_msg_for_dm", @"Vector", nil);
}
else
{
title = NSLocalizedStringFromTable(@"room_participants_leave_prompt_title", @"Vector", nil);
message = NSLocalizedStringFromTable(@"room_participants_leave_prompt_msg", @"Vector", nil);
}
currentAlert = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"room_participants_leave_prompt_title", @"Vector", nil)
message:NSLocalizedStringFromTable(@"room_participants_leave_prompt_msg", @"Vector", nil)
currentAlert = [UIAlertController alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
[currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"]

View file

@ -35,8 +35,6 @@
@interface RoomTitleView : MXKRoomTitleView <UIGestureRecognizerDelegate>
@property (weak, nonatomic) IBOutlet UIView *titleMask;
@property (weak, nonatomic) IBOutlet UIView *roomDetailsMask;
@property (weak, nonatomic) IBOutlet UIView *addParticipantMask;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *displayNameCenterXConstraint;
@property (weak, nonatomic) IBOutlet UIImageView *roomDetailsIconImageView;
@property (weak, nonatomic) IBOutlet UIImageView *badgeImageView;

View file

@ -48,26 +48,6 @@
[self.titleMask addGestureRecognizer:tap];
self.titleMask.userInteractionEnabled = YES;
}
if (_roomDetailsMask)
{
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(reportTapGesture:)];
[tap setNumberOfTouchesRequired:1];
[tap setNumberOfTapsRequired:1];
[tap setDelegate:self];
[self.roomDetailsMask addGestureRecognizer:tap];
self.roomDetailsMask.userInteractionEnabled = YES;
}
if (_addParticipantMask)
{
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(reportTapGesture:)];
[tap setNumberOfTouchesRequired:1];
[tap setNumberOfTapsRequired:1];
[tap setDelegate:self];
[self.addParticipantMask addGestureRecognizer:tap];
self.addParticipantMask.userInteractionEnabled = YES;
}
}
- (void)layoutSubviews

View file

@ -1,11 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16096" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -16,7 +14,7 @@
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="encryption_normal" translatesAutoresizingMaskIntoConstraints="NO" id="Ky3-cy-HAx">
<rect key="frame" x="229.5" y="13" width="14" height="14"/>
<rect key="frame" x="231.5" y="13.5" width="14" height="14"/>
<accessibility key="accessibilityConfiguration" identifier="RoomDetailsIconImageView"/>
<constraints>
<constraint firstAttribute="width" constant="14" id="7xE-aD-sld"/>
@ -24,7 +22,7 @@
</constraints>
</imageView>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="Room Name" textAlignment="center" adjustsFontSizeToFit="NO" minimumFontSize="14" translatesAutoresizingMaskIntoConstraints="NO" id="6uH-I3-RQg">
<rect key="frame" x="247.5" y="9" width="105" height="22"/>
<rect key="frame" x="249.5" y="9" width="101" height="23"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="DisplayNameTextField"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="18"/>
@ -34,7 +32,7 @@
</connections>
</textField>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="details_icon" translatesAutoresizingMaskIntoConstraints="NO" id="S3Y-wJ-HOe">
<rect key="frame" x="359.5" y="14" width="6" height="12"/>
<rect key="frame" x="357.5" y="14.5" width="6" height="12"/>
<accessibility key="accessibilityConfiguration" identifier="RoomDetailsIconImageView"/>
<constraints>
<constraint firstAttribute="width" constant="6" id="XTx-6p-2wB"/>
@ -42,11 +40,7 @@
</constraints>
</imageView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sD9-l7-azQ">
<rect key="frame" x="0.0" y="0.0" width="352.5" height="44"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="pFg-XE-6DB">
<rect key="frame" x="352.5" y="0.0" width="247.5" height="44"/>
<rect key="frame" x="0.0" y="0.0" width="600" height="44"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</view>
</subviews>
@ -57,19 +51,15 @@
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="S3Y-wJ-HOe" secondAttribute="trailing" id="3z3-Ye-wh3"/>
<constraint firstAttribute="bottom" secondItem="sD9-l7-azQ" secondAttribute="bottom" id="4rX-5O-LrO"/>
<constraint firstItem="sD9-l7-azQ" firstAttribute="leading" secondItem="BkF-x3-7fX" secondAttribute="leading" id="AJc-Aa-sht"/>
<constraint firstItem="sD9-l7-azQ" firstAttribute="trailing" secondItem="6uH-I3-RQg" secondAttribute="trailing" id="DnD-l9-v0F"/>
<constraint firstItem="pFg-XE-6DB" firstAttribute="leading" secondItem="sD9-l7-azQ" secondAttribute="trailing" id="Gxi-oJ-gpi"/>
<constraint firstAttribute="bottom" secondItem="pFg-XE-6DB" secondAttribute="bottom" id="HEU-GL-4yt"/>
<constraint firstAttribute="trailing" secondItem="pFg-XE-6DB" secondAttribute="trailing" id="HPm-vM-32l"/>
<constraint firstItem="S3Y-wJ-HOe" firstAttribute="centerY" secondItem="6uH-I3-RQg" secondAttribute="centerY" id="Jjq-ss-0kj"/>
<constraint firstItem="6uH-I3-RQg" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="BkF-x3-7fX" secondAttribute="leading" constant="8" id="KW6-05-QLM"/>
<constraint firstItem="6uH-I3-RQg" firstAttribute="leading" secondItem="Ky3-cy-HAx" secondAttribute="trailing" constant="4" id="Kis-Qb-UuJ"/>
<constraint firstItem="pFg-XE-6DB" firstAttribute="top" secondItem="BkF-x3-7fX" secondAttribute="top" id="M4X-tH-OCM"/>
<constraint firstItem="Ky3-cy-HAx" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="BkF-x3-7fX" secondAttribute="leading" id="MHL-wh-61l"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="6uH-I3-RQg" secondAttribute="trailing" constant="8" id="PUM-di-dAZ"/>
<constraint firstItem="6uH-I3-RQg" firstAttribute="top" secondItem="BkF-x3-7fX" secondAttribute="top" constant="9" id="Piq-rp-Pae"/>
<constraint firstItem="sD9-l7-azQ" firstAttribute="top" secondItem="BkF-x3-7fX" secondAttribute="top" id="YrR-1c-h56"/>
<constraint firstItem="Ky3-cy-HAx" firstAttribute="centerY" secondItem="6uH-I3-RQg" secondAttribute="centerY" id="ayN-Hv-q7s"/>
<constraint firstAttribute="trailing" secondItem="sD9-l7-azQ" secondAttribute="trailing" id="q9f-Hp-g5N"/>
<constraint firstItem="S3Y-wJ-HOe" firstAttribute="leading" secondItem="6uH-I3-RQg" secondAttribute="trailing" constant="7" id="qbS-km-tTO"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
@ -79,7 +69,6 @@
<outlet property="displayNameTextField" destination="6uH-I3-RQg" id="MfX-LQ-C2K"/>
<outlet property="displayNameTextFieldTopConstraint" destination="Piq-rp-Pae" id="jnL-Hz-TWn"/>
<outlet property="roomDetailsIconImageView" destination="S3Y-wJ-HOe" id="bhR-6E-8St"/>
<outlet property="roomDetailsMask" destination="pFg-XE-6DB" id="7EF-K5-G0o"/>
<outlet property="titleMask" destination="sD9-l7-azQ" id="I9b-wF-iNH"/>
</connections>
<point key="canvasLocation" x="137.59999999999999" y="153.82308845577214"/>

View file

@ -25,7 +25,7 @@
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
</view>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="s5V-FE-qJ3" firstAttribute="top" secondItem="h8p-zd-Pue" secondAttribute="top" constant="16" id="5n9-Dz-sa1"/>
<constraint firstAttribute="trailing" secondItem="s5V-FE-qJ3" secondAttribute="trailing" constant="16" id="Cd9-ae-0kJ"/>
@ -73,7 +73,7 @@
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="BPe-c4-SLl" secondAttribute="bottom" constant="8" id="Bt1-v4-QJi"/>
<constraint firstItem="BPe-c4-SLl" firstAttribute="top" secondItem="Epc-BZ-uFU" secondAttribute="top" constant="8" id="hKE-aL-wux"/>
@ -105,7 +105,7 @@
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</activityIndicatorView>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="xFW-zA-lpm" firstAttribute="leading" secondItem="3aU-yC-Wow" secondAttribute="leading" constant="8" id="7mq-Cv-Xfy"/>
<constraint firstItem="xFW-zA-lpm" firstAttribute="centerY" secondItem="3aU-yC-Wow" secondAttribute="centerY" id="Qhe-td-fRv"/>
@ -118,6 +118,7 @@
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="Epc-BZ-uFU" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" id="1DL-b0-Pxs"/>
<constraint firstAttribute="bottom" secondItem="3aU-yC-Wow" secondAttribute="bottom" id="1o4-dx-PVC"/>

View file

@ -78,8 +78,12 @@
<viewLayoutGuide key="safeArea" id="PMt-fQ-rFh"/>
</view>
<connections>
<outlet property="blurEffectContentView" destination="4ka-0i-i4y" id="xYO-0s-q7b"/>
<outlet property="blurEffectView" destination="Sbh-JU-SHP" id="mUv-Wg-ku9"/>
<outlet property="createRoomButton" destination="qGk-Os-0Dj" id="eGX-z9-mAi"/>
<outlet property="mainTableView" destination="hBr-zt-GEh" id="erE-8r-vuc"/>
<outlet property="vibrancyEffectContentView" destination="o3H-fV-geh" id="4zA-HE-umG"/>
<outlet property="vibrancyEffectView" destination="shK-Lq-qu8" id="f0q-fp-Ofp"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="lCT-2C-Scp" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>

View file

@ -27,6 +27,10 @@ final class ShowDirectoryViewController: UIViewController {
// MARK: Outlets
@IBOutlet private weak var mainTableView: UITableView!
@IBOutlet private weak var vibrancyEffectView: UIVisualEffectView!
@IBOutlet private weak var vibrancyEffectContentView: UIView!
@IBOutlet private weak var blurEffectView: UIVisualEffectView!
@IBOutlet private weak var blurEffectContentView: UIView!
@IBOutlet private weak var createRoomButton: UIButton! {
didSet {
createRoomButton.setTitle(VectorL10n.searchableDirectoryCreateNewRoom, for: .normal)
@ -130,6 +134,12 @@ final class ShowDirectoryViewController: UIViewController {
theme.applyStyle(onSearchBar: mainSearchBar)
theme.applyStyle(onButton: createRoomButton)
if #available(iOS 13.0, *) {
vibrancyEffectView.overrideUserInterfaceStyle = theme.userInterfaceStyle
vibrancyEffectContentView.overrideUserInterfaceStyle = theme.userInterfaceStyle
blurEffectView.overrideUserInterfaceStyle = theme.userInterfaceStyle
blurEffectContentView.overrideUserInterfaceStyle = theme.userInterfaceStyle
}
self.mainTableView.reloadData()
}

View file

@ -59,4 +59,8 @@ extension SecretsRecoveryWithKeyCoordinator: SecretsRecoveryWithKeyViewModelCoor
func secretsRecoveryWithKeyViewModelDidCancel(_ viewModel: SecretsRecoveryWithKeyViewModelType) { self.delegate?.secretsRecoveryWithKeyCoordinatorDidCancel(self)
}
func secretsRecoveryWithKeyViewModelWantsToResetSecrets(_ viewModel: SecretsRecoveryWithKeyViewModelType) {
self.delegate?.secretsRecoveryWithKeyCoordinatorWantsToResetSecrets(self)
}
}

View file

@ -19,6 +19,7 @@ import Foundation
protocol SecretsRecoveryWithKeyCoordinatorDelegate: class {
func secretsRecoveryWithKeyCoordinatorDidRecover(_ coordinator: SecretsRecoveryWithKeyCoordinatorType)
func secretsRecoveryWithKeyCoordinatorDidCancel(_ coordinator: SecretsRecoveryWithKeyCoordinatorType)
func secretsRecoveryWithKeyCoordinatorWantsToResetSecrets(_ viewModel: SecretsRecoveryWithKeyCoordinatorType)
}
/// `SecretsRecoveryWithKeyCoordinatorType` is a protocol describing a Coordinator that handle secrets recovery from recovery key navigation flow.

View file

@ -18,6 +18,7 @@ import Foundation
/// SecretsRecoveryWithKeyViewController view actions exposed to view model
enum SecretsRecoveryWithKeyViewAction {
case recover
case recover
case resetSecrets
case cancel
}

View file

@ -1,11 +1,9 @@
<?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="xgV-qW-Fsz">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097.3" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="xgV-qW-Fsz">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@ -19,13 +17,13 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lGc-J1-CgX">
<rect key="frame" x="0.0" y="20" width="375" height="647"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="byL-eq-NOk">
<rect key="frame" x="0.0" y="0.0" width="375" height="377"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="443"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lYT-Tl-Mah">
<rect key="frame" x="0.0" y="0.0" width="375" height="377"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="443"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="secrets_recovery_key" translatesAutoresizingMaskIntoConstraints="NO" id="eS4-VO-THO">
<rect key="frame" x="165.5" y="35" width="44" height="48"/>
@ -54,7 +52,6 @@
<constraints>
<constraint firstAttribute="height" constant="50" id="3ip-DB-fLs"/>
</constraints>
<nil key="textColor"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" returnKeyType="done"/>
<connections>
@ -120,20 +117,40 @@
<constraint firstItem="HrF-Jh-mlh" firstAttribute="top" secondItem="xo4-pw-QbA" secondAttribute="top" id="dr9-B3-nAt"/>
</constraints>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="PPL-j2-hnv">
<rect key="frame" x="0.0" y="373" width="375" height="50"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="ORA-ea-g34"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<inset key="contentEdgeInsets" minX="20" minY="0.0" maxX="20" maxY="0.0"/>
<state key="normal" title="Forgot or lost all recovery options? Reset everything">
<color key="titleColor" cocoaTouchSystemColor="darkTextColor"/>
</state>
<state key="disabled">
<color key="titleColor" red="0.47843137250000001" green="0.78823529410000004" blue="0.63137254899999995" alpha="0.5" colorSpace="calibratedRGB"/>
</state>
<connections>
<action selector="resetSecretsAction:" destination="xgV-qW-Fsz" eventType="touchUpInside" id="vaK-ot-P1e"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="xo4-pw-QbA" secondAttribute="bottom" constant="20" id="0B3-c2-ro5"/>
<constraint firstItem="v8b-un-B61" firstAttribute="top" secondItem="nE7-cw-Z30" secondAttribute="bottom" constant="40" id="0OM-LN-FIF"/>
<constraint firstAttribute="trailing" secondItem="nE7-cw-Z30" secondAttribute="trailing" constant="20" id="25y-AS-2UT"/>
<constraint firstItem="xo4-pw-QbA" firstAttribute="leading" secondItem="lYT-Tl-Mah" secondAttribute="leading" id="5h3-ut-ljD"/>
<constraint firstItem="nE7-cw-Z30" firstAttribute="top" secondItem="eS4-VO-THO" secondAttribute="bottom" constant="30" id="87H-5c-7L4"/>
<constraint firstItem="eS4-VO-THO" firstAttribute="top" secondItem="lYT-Tl-Mah" secondAttribute="top" constant="35" id="JwA-G2-VIj"/>
<constraint firstItem="PPL-j2-hnv" firstAttribute="leading" secondItem="lYT-Tl-Mah" secondAttribute="leading" id="L4S-8s-L8O"/>
<constraint firstAttribute="trailing" secondItem="v8b-un-B61" secondAttribute="trailing" id="MIp-Z4-OI9"/>
<constraint firstItem="v8b-un-B61" firstAttribute="leading" secondItem="lYT-Tl-Mah" secondAttribute="leading" id="XIH-Fa-RSj"/>
<constraint firstAttribute="bottom" secondItem="PPL-j2-hnv" secondAttribute="bottom" constant="20" id="XKs-5K-o7w"/>
<constraint firstItem="eS4-VO-THO" firstAttribute="centerX" secondItem="lYT-Tl-Mah" secondAttribute="centerX" id="YZk-TW-2Yb"/>
<constraint firstAttribute="trailing" secondItem="xo4-pw-QbA" secondAttribute="trailing" id="fWz-BT-edl"/>
<constraint firstItem="PPL-j2-hnv" firstAttribute="top" secondItem="xo4-pw-QbA" secondAttribute="bottom" constant="16" id="lUh-Qo-meH"/>
<constraint firstItem="nE7-cw-Z30" firstAttribute="leading" secondItem="lYT-Tl-Mah" secondAttribute="leading" constant="20" id="ooI-aS-mXQ"/>
<constraint firstAttribute="trailing" secondItem="PPL-j2-hnv" secondAttribute="trailing" id="qHl-BD-M1y"/>
<constraint firstAttribute="width" priority="750" constant="500" id="qpC-Rx-87A"/>
<constraint firstItem="xo4-pw-QbA" firstAttribute="top" secondItem="v8b-un-B61" secondAttribute="bottom" constant="50" id="xiD-aT-T0f"/>
</constraints>
@ -174,6 +191,7 @@
<outlet property="recoveryKeyTextField" destination="e79-U2-RHY" id="xEP-LQ-rKR"/>
<outlet property="recoveryKeyTextFieldBackgroundView" destination="v8b-un-B61" id="YIA-Sn-A22"/>
<outlet property="recoveryKeyTitleLabel" destination="UdR-PC-WoG" id="R8h-o0-2tR"/>
<outlet property="resetSecretsButton" destination="PPL-j2-hnv" id="Nec-yK-DkU"/>
<outlet property="scrollView" destination="lGc-J1-CgX" id="9Il-vB-zoh"/>
<outlet property="shieldImageView" destination="eS4-VO-THO" id="P6x-QL-Mqv"/>
</connections>

View file

@ -36,6 +36,8 @@ final class SecretsRecoveryWithKeyViewController: UIViewController {
@IBOutlet private weak var importFileButton: UIButton!
@IBOutlet private weak var recoverButton: RoundedButton!
@IBOutlet private weak var resetSecretsButton: UIButton!
// MARK: Private
@ -117,6 +119,8 @@ final class SecretsRecoveryWithKeyViewController: UIViewController {
self.recoverButton.setTitle(VectorL10n.secretsRecoveryWithKeyRecoverAction, for: .normal)
self.updateRecoverButton()
self.resetSecretsButton.vc_enableMultiLinesTitle()
}
private func update(theme: Theme) {
@ -140,6 +144,15 @@ final class SecretsRecoveryWithKeyViewController: UIViewController {
theme.applyStyle(onButton: self.importFileButton)
self.recoverButton.update(theme: theme)
// Reset secrets button
let resetSecretsAttributedString = NSMutableAttributedString(string: VectorL10n.secretsRecoveryResetActionPart1, attributes: [.foregroundColor: self.theme.textPrimaryColor])
let resetSecretsAttributedStringPart2 = NSAttributedString(string: VectorL10n.secretsRecoveryResetActionPart2, attributes: [.foregroundColor: self.theme.warningColor])
resetSecretsAttributedString.append(resetSecretsAttributedStringPart2)
self.resetSecretsButton.setAttributedTitle(resetSecretsAttributedString, for: .normal)
}
private func registerThemeServiceDidChangeThemeNotification() {
@ -241,6 +254,10 @@ final class SecretsRecoveryWithKeyViewController: UIViewController {
@IBAction private func recoverButtonAction(_ sender: Any) {
self.viewModel.process(viewAction: .recover)
}
@IBAction private func resetSecretsAction(_ sender: Any) {
self.viewModel.process(viewAction: .resetSecrets)
}
}
// MARK: - UITextFieldDelegate

View file

@ -50,6 +50,8 @@ final class SecretsRecoveryWithKeyViewModel: SecretsRecoveryWithKeyViewModelType
switch viewAction {
case .recover:
self.recover()
case .resetSecrets:
self.coordinatorDelegate?.secretsRecoveryWithKeyViewModelWantsToResetSecrets(self)
case .cancel:
self.coordinatorDelegate?.secretsRecoveryWithKeyViewModelDidCancel(self)
}

View file

@ -23,6 +23,7 @@ protocol SecretsRecoveryWithKeyViewModelViewDelegate: class {
protocol SecretsRecoveryWithKeyViewModelCoordinatorDelegate: class {
func secretsRecoveryWithKeyViewModelDidRecover(_ viewModel: SecretsRecoveryWithKeyViewModelType)
func secretsRecoveryWithKeyViewModelDidCancel(_ viewModel: SecretsRecoveryWithKeyViewModelType)
func secretsRecoveryWithKeyViewModelWantsToResetSecrets(_ viewModel: SecretsRecoveryWithKeyViewModelType)
}
/// Protocol describing the view model used by `SecretsRecoveryWithPassphraseViewController`

View file

@ -57,9 +57,15 @@ extension SecretsRecoveryWithPassphraseCoordinator: SecretsRecoveryWithPassphras
self.delegate?.secretsRecoveryWithPassphraseCoordinatorDoNotKnowPassphrase(self)
}
func secretsRecoveryWithPassphraseViewModelDidRecover(_ viewModel: SecretsRecoveryWithPassphraseViewModelType) { self.delegate?.secretsRecoveryWithPassphraseCoordinatorDidRecover(self)
func secretsRecoveryWithPassphraseViewModelDidRecover(_ viewModel: SecretsRecoveryWithPassphraseViewModelType) {
self.delegate?.secretsRecoveryWithPassphraseCoordinatorDidRecover(self)
}
func secretsRecoveryWithPassphraseViewModelDidCancel(_ viewModel: SecretsRecoveryWithPassphraseViewModelType) { self.delegate?.secretsRecoveryWithPassphraseCoordinatorDidCancel(self)
}
func secretsRecoveryWithPassphraseViewModelDidCancel(_ viewModel: SecretsRecoveryWithPassphraseViewModelType) {
self.delegate?.secretsRecoveryWithPassphraseCoordinatorDidCancel(self)
}
func secretsRecoveryWithPassphraseViewModelWantsToResetSecrets(_ viewModel: SecretsRecoveryWithPassphraseViewModelType) {
self.delegate?.secretsRecoveryWithPassphraseCoordinatorWantsToResetSecrets(self)
}
}

View file

@ -20,6 +20,7 @@ protocol SecretsRecoveryWithPassphraseCoordinatorDelegate: class {
func secretsRecoveryWithPassphraseCoordinatorDidRecover(_ coordinator: SecretsRecoveryWithPassphraseCoordinatorType)
func secretsRecoveryWithPassphraseCoordinatorDoNotKnowPassphrase(_ coordinator: SecretsRecoveryWithPassphraseCoordinatorType)
func secretsRecoveryWithPassphraseCoordinatorDidCancel(_ coordinator: SecretsRecoveryWithPassphraseCoordinatorType)
func secretsRecoveryWithPassphraseCoordinatorWantsToResetSecrets(_ coordinator: SecretsRecoveryWithPassphraseCoordinatorType)
}
/// `SecretsRecoveryWithPassphraseCoordinatorType` is a protocol describing a Coordinator that handle key backup passphrase recover navigation flow.

View file

@ -20,5 +20,6 @@ import Foundation
enum SecretsRecoveryWithPassphraseViewAction {
case recover
case useRecoveryKey
case resetSecrets
case cancel
}

View file

@ -1,11 +1,9 @@
<?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="KkK-aQ-7Ig">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097.3" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="KkK-aQ-7Ig">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@ -19,13 +17,13 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="FYl-Bb-Kpe">
<rect key="frame" x="0.0" y="20" width="375" height="647"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="dlf-fL-IPA">
<rect key="frame" x="0.0" y="0.0" width="375" height="423"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="489"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Gw9-uS-bGl">
<rect key="frame" x="0.0" y="0.0" width="375" height="423"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="489"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="secrets_recovery_passphrase" translatesAutoresizingMaskIntoConstraints="NO" id="hA4-wJ-xGz">
<rect key="frame" x="165.5" y="35" width="44" height="48"/>
@ -55,7 +53,6 @@
<constraints>
<constraint firstAttribute="height" constant="50" id="iy4-UK-b6r"/>
</constraints>
<nil key="textColor"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" returnKeyType="done" secureTextEntry="YES"/>
<connections>
@ -136,21 +133,41 @@
<constraint firstItem="DpI-8g-yKB" firstAttribute="width" secondItem="zOv-dc-49b" secondAttribute="width" priority="750" id="q7z-h9-oc7"/>
</constraints>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="FsM-8o-pIc">
<rect key="frame" x="0.0" y="419" width="375" height="50"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="Zb9-Il-WIS"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<inset key="contentEdgeInsets" minX="20" minY="0.0" maxX="20" maxY="0.0"/>
<state key="normal" title="Forgot or lost all recovery options? Reset everything">
<color key="titleColor" cocoaTouchSystemColor="darkTextColor"/>
</state>
<state key="disabled">
<color key="titleColor" red="0.47843137250000001" green="0.78823529410000004" blue="0.63137254899999995" alpha="0.5" colorSpace="calibratedRGB"/>
</state>
<connections>
<action selector="resetSecretsAction:" destination="KkK-aQ-7Ig" eventType="touchUpInside" id="gCT-4A-pG6"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="zOv-dc-49b" secondAttribute="bottom" constant="20" id="3Wl-WT-6Et"/>
<constraint firstAttribute="trailing" secondItem="uly-5I-NIc" secondAttribute="trailing" id="6VB-MQ-hIp"/>
<constraint firstItem="p2V-aL-g0y" firstAttribute="top" secondItem="hA4-wJ-xGz" secondAttribute="bottom" constant="30" id="6eX-cP-a3F"/>
<constraint firstAttribute="trailing" secondItem="zOv-dc-49b" secondAttribute="trailing" id="9er-kg-arg"/>
<constraint firstItem="FsM-8o-pIc" firstAttribute="top" secondItem="zOv-dc-49b" secondAttribute="bottom" constant="16" id="KfQ-rd-n2B"/>
<constraint firstAttribute="width" priority="750" constant="500" id="NAT-Cc-oHN"/>
<constraint firstItem="a20-Ii-sAN" firstAttribute="top" secondItem="uly-5I-NIc" secondAttribute="bottom" constant="16" id="P9q-sL-AcP"/>
<constraint firstItem="p2V-aL-g0y" firstAttribute="leading" secondItem="Gw9-uS-bGl" secondAttribute="leading" constant="20" id="VM5-6u-8kW"/>
<constraint firstItem="uly-5I-NIc" firstAttribute="top" secondItem="p2V-aL-g0y" secondAttribute="bottom" constant="40" id="b6d-xb-RsF"/>
<constraint firstItem="zOv-dc-49b" firstAttribute="top" secondItem="a20-Ii-sAN" secondAttribute="bottom" constant="30" id="b6e-I5-UmV"/>
<constraint firstItem="zOv-dc-49b" firstAttribute="leading" secondItem="Gw9-uS-bGl" secondAttribute="leading" id="bdZ-LL-sEK"/>
<constraint firstAttribute="bottom" secondItem="FsM-8o-pIc" secondAttribute="bottom" constant="20" id="cFV-lL-sr0"/>
<constraint firstItem="uly-5I-NIc" firstAttribute="leading" secondItem="Gw9-uS-bGl" secondAttribute="leading" id="cbx-lF-FxP"/>
<constraint firstItem="FsM-8o-pIc" firstAttribute="leading" secondItem="Gw9-uS-bGl" secondAttribute="leading" id="dlb-Mp-dHQ"/>
<constraint firstAttribute="trailing" secondItem="p2V-aL-g0y" secondAttribute="trailing" constant="20" id="ebM-3Y-G7G"/>
<constraint firstAttribute="trailing" secondItem="FsM-8o-pIc" secondAttribute="trailing" id="jtO-Hw-15P"/>
<constraint firstItem="hA4-wJ-xGz" firstAttribute="centerX" secondItem="Gw9-uS-bGl" secondAttribute="centerX" id="v1j-88-njw"/>
<constraint firstAttribute="trailing" secondItem="a20-Ii-sAN" secondAttribute="trailing" id="ysR-iF-6Wq"/>
<constraint firstItem="hA4-wJ-xGz" firstAttribute="top" secondItem="Gw9-uS-bGl" secondAttribute="top" constant="35" id="zVj-yd-Zo3"/>
@ -195,6 +212,7 @@
<outlet property="passphraseTitleLabel" destination="I7Q-Tb-YGd" id="jrA-8B-fsw"/>
<outlet property="passphraseVisibilityButton" destination="ahr-Zq-UM4" id="95l-go-Yjj"/>
<outlet property="recoverButton" destination="DpI-8g-yKB" id="aA6-fD-whb"/>
<outlet property="resetSecretsButton" destination="FsM-8o-pIc" id="kKO-9G-JZD"/>
<outlet property="scrollView" destination="FYl-Bb-Kpe" id="jR3-VH-AdU"/>
<outlet property="shieldImageView" destination="hA4-wJ-xGz" id="MPg-q1-UVx"/>
<outlet property="useRecoveryKeyButton" destination="a20-Ii-sAN" id="ZMQ-PQ-jEn"/>

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