mirror of
https://github.com/vector-im/element-ios.git
synced 2024-09-28 23:32:41 +00:00
Merge branch 'develop' into element_3776
This commit is contained in:
commit
a8f7713a16
11 changed files with 262 additions and 138 deletions
|
@ -2,9 +2,10 @@ Changes to be released in next version
|
|||
=================================================
|
||||
|
||||
✨ Features
|
||||
*
|
||||
* Enable encryption for accounts, contacts and keys in the crypto database (#3867).
|
||||
|
||||
🙌 Improvements
|
||||
* Home: Show room directory on join room action (#3775).
|
||||
* RoomVC: Add quick actions in timeline on room creation (#3776).
|
||||
|
||||
🐛 Bugfix
|
||||
|
|
|
@ -72,6 +72,9 @@ class CommonConfiguration: NSObject, Configurable {
|
|||
|
||||
// Disable key backup on common
|
||||
sdkOptions.enableKeyBackupWhenStartingMXCrypto = false
|
||||
|
||||
// Configure key provider delegate
|
||||
MXKeyProvider.sharedInstance().delegate = EncryptionKeyManager.shared
|
||||
}
|
||||
|
||||
|
||||
|
|
14
Podfile.lock
14
Podfile.lock
|
@ -74,16 +74,16 @@ PODS:
|
|||
- AFNetworking (~> 4.0.0)
|
||||
- GZIP (~> 1.3.0)
|
||||
- libbase58 (~> 0.1.4)
|
||||
- OLMKit (~> 3.1.0)
|
||||
- OLMKit (~> 3.2.2)
|
||||
- Realm (= 10.1.4)
|
||||
- MatrixSDK/JingleCallStack (0.18.1):
|
||||
- JitsiMeetSDK (= 3.1.0)
|
||||
- MatrixSDK/Core
|
||||
- OLMKit (3.1.0):
|
||||
- OLMKit/olmc (= 3.1.0)
|
||||
- OLMKit/olmcpp (= 3.1.0)
|
||||
- OLMKit/olmc (3.1.0)
|
||||
- OLMKit/olmcpp (3.1.0)
|
||||
- OLMKit (3.2.2):
|
||||
- OLMKit/olmc (= 3.2.2)
|
||||
- OLMKit/olmcpp (= 3.2.2)
|
||||
- OLMKit/olmc (3.2.2)
|
||||
- OLMKit/olmcpp (3.2.2)
|
||||
- ReadMoreTextView (3.0.1)
|
||||
- Realm (10.1.4):
|
||||
- Realm/Headers (= 10.1.4)
|
||||
|
@ -188,7 +188,7 @@ SPEC CHECKSUMS:
|
|||
MatomoTracker: a59ec4da0f580be57bdc6baa708a71a86532a832
|
||||
MatrixKit: 267c3235abae2e3878e41a57bda32ec4899118e6
|
||||
MatrixSDK: 7d5faf810eab02a189df64aef28583c8bed81f5c
|
||||
OLMKit: 4ee0159d63feeb86d836fdcfefe418e163511639
|
||||
OLMKit: 20d1c564033a1ae7148f8f599378d4c798363905
|
||||
ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d
|
||||
Realm: 80f4fb2971ccb9adc27a47d0955ae8e533a7030b
|
||||
Reusable: 53a9acf5c536f229b31b5865782414b508252ddb
|
||||
|
|
128
Riot/Managers/EncryptionKeyManager/EncryptionKeyManager.swift
Normal file
128
Riot/Managers/EncryptionKeyManager/EncryptionKeyManager.swift
Normal file
|
@ -0,0 +1,128 @@
|
|||
//
|
||||
// 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 KeychainAccess
|
||||
import MatrixKit
|
||||
import CommonCrypto
|
||||
|
||||
@objcMembers
|
||||
class EncryptionKeyManager: NSObject, MXKeyProviderDelegate {
|
||||
static let shared = EncryptionKeyManager()
|
||||
|
||||
private static let keychainService: String = BuildSettings.baseBundleIdentifier + ".encryption-manager-service"
|
||||
private static let contactsIv: KeyValueStoreKey = "contactsIv"
|
||||
private static let contactsAesKey: KeyValueStoreKey = "contactsAesKey"
|
||||
private static let accountIv: KeyValueStoreKey = "accountIv"
|
||||
private static let accountAesKey: KeyValueStoreKey = "accountAesKey"
|
||||
private static let cryptoOlmPickleKey: KeyValueStoreKey = "cryptoOlmPickleKey"
|
||||
|
||||
private let keychainStore: KeyValueStore = KeychainStore(withKeychain: Keychain(service: keychainService, accessGroup: BuildSettings.keychainAccessGroup))
|
||||
|
||||
private override init() {
|
||||
super.init()
|
||||
initKeys()
|
||||
}
|
||||
|
||||
private func initKeys() {
|
||||
generateIvIfNotExists(forKey: EncryptionKeyManager.accountIv)
|
||||
generateAesKeyIfNotExists(forKey: EncryptionKeyManager.accountAesKey)
|
||||
generateIvIfNotExists(forKey: EncryptionKeyManager.contactsIv)
|
||||
generateAesKeyIfNotExists(forKey: EncryptionKeyManager.contactsAesKey)
|
||||
generateKeyIfNotExists(forKey: EncryptionKeyManager.cryptoOlmPickleKey, size: 32)
|
||||
|
||||
assert(keychainStore.containsObject(forKey: EncryptionKeyManager.contactsIv), "[EncryptionKeyManager] initKeys: Failed to generate IV for acount")
|
||||
assert(keychainStore.containsObject(forKey: EncryptionKeyManager.contactsAesKey), "[EncryptionKeyManager] initKeys: Failed to generate AES Key for acount")
|
||||
assert(keychainStore.containsObject(forKey: EncryptionKeyManager.contactsIv), "[EncryptionKeyManager] initKeys: Failed to generate IV for contacts")
|
||||
assert(keychainStore.containsObject(forKey: EncryptionKeyManager.contactsAesKey), "[EncryptionKeyManager] initKeys: Failed to generate AES Key for contacts")
|
||||
assert(keychainStore.containsObject(forKey: EncryptionKeyManager.cryptoOlmPickleKey), "[EncryptionKeyManager] initKeys: Failed to generate Key for olm pickle key")
|
||||
}
|
||||
|
||||
// MARK: - MXKeyProviderDelegate
|
||||
|
||||
func isEncryptionAvailableForData(ofType dataType: String) -> Bool {
|
||||
return dataType == MXKContactManagerDataType
|
||||
|| dataType == MXKAccountManagerDataType
|
||||
|| dataType == MXCryptoOlmPickleKeyDataType
|
||||
}
|
||||
|
||||
func hasKeyForData(ofType dataType: String) -> Bool {
|
||||
switch dataType {
|
||||
case MXKContactManagerDataType:
|
||||
return keychainStore.containsObject(forKey: EncryptionKeyManager.contactsIv) && keychainStore.containsObject(forKey: EncryptionKeyManager.contactsAesKey)
|
||||
case MXKAccountManagerDataType:
|
||||
return keychainStore.containsObject(forKey: EncryptionKeyManager.accountIv) && keychainStore.containsObject(forKey: EncryptionKeyManager.accountAesKey)
|
||||
case MXCryptoOlmPickleKeyDataType:
|
||||
return keychainStore.containsObject(forKey: EncryptionKeyManager.cryptoOlmPickleKey)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func keyDataForData(ofType dataType: String) -> MXKeyData? {
|
||||
switch dataType {
|
||||
case MXKContactManagerDataType:
|
||||
if let ivKey = try? keychainStore.data(forKey: EncryptionKeyManager.contactsIv),
|
||||
let aesKey = try? keychainStore.data(forKey: EncryptionKeyManager.contactsAesKey) {
|
||||
return MXAesKeyData(iv: ivKey, key: aesKey)
|
||||
}
|
||||
case MXKAccountManagerDataType:
|
||||
if let ivKey = try? keychainStore.data(forKey: EncryptionKeyManager.accountIv),
|
||||
let aesKey = try? keychainStore.data(forKey: EncryptionKeyManager.accountAesKey) {
|
||||
return MXAesKeyData(iv: ivKey, key: aesKey)
|
||||
}
|
||||
case MXCryptoOlmPickleKeyDataType:
|
||||
if let key = try? keychainStore.data(forKey: EncryptionKeyManager.cryptoOlmPickleKey) {
|
||||
return MXRawDataKey(key: key)
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MARK: - Private methods
|
||||
|
||||
private func generateIvIfNotExists(forKey key: String) {
|
||||
guard !keychainStore.containsObject(forKey: key) else {
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
try keychainStore.set(MXAes.iv(), forKey: key)
|
||||
} catch {
|
||||
NSLog("[EncryptionKeyManager] initKeys: Failed to generate IV: %@", error.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
||||
private func generateAesKeyIfNotExists(forKey key: String) {
|
||||
generateKeyIfNotExists(forKey: key, size: kCCKeySizeAES256)
|
||||
}
|
||||
|
||||
private func generateKeyIfNotExists(forKey key: String, size: Int) {
|
||||
guard !keychainStore.containsObject(forKey: key) else {
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
var keyBytes = [UInt8](repeating: 0, count: size)
|
||||
_ = SecRandomCopyBytes(kSecRandomDefault, size, &keyBytes)
|
||||
try keychainStore.set(Data(bytes: keyBytes, count: size), forKey: key)
|
||||
} catch {
|
||||
NSLog("[EncryptionKeyManager] initKeys: Failed to generate Key[%@]: %@", key, error.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -165,6 +165,16 @@
|
|||
*/
|
||||
- (void)muteEditedRoomNotifications:(BOOL)mute;
|
||||
|
||||
/**
|
||||
Show room directory.
|
||||
*/
|
||||
- (void)showRoomDirectory;
|
||||
|
||||
/**
|
||||
Show a public room.
|
||||
*/
|
||||
- (void)openPublicRoom:(MXPublicRoom *)publicRoom;
|
||||
|
||||
#pragma mark - Scrolling
|
||||
|
||||
/**
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
#import "Riot-Swift.h"
|
||||
|
||||
@interface RecentsViewController () <CreateRoomCoordinatorBridgePresenterDelegate>
|
||||
@interface RecentsViewController () <CreateRoomCoordinatorBridgePresenterDelegate, RoomsDirectoryCoordinatorBridgePresenterDelegate>
|
||||
{
|
||||
// Tell whether a recents refresh is pending (suspended during editing mode).
|
||||
BOOL isRefreshPending;
|
||||
|
@ -68,6 +68,8 @@
|
|||
|
||||
@property (nonatomic, strong) CreateRoomCoordinatorBridgePresenter *createRoomCoordinatorBridgePresenter;
|
||||
|
||||
@property (nonatomic, strong) RoomsDirectoryCoordinatorBridgePresenter *roomsDirectoryCoordinatorBridgePresenter;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RecentsViewController
|
||||
|
@ -856,6 +858,18 @@
|
|||
self.view.userInteractionEnabled = userInteractionEnabled;
|
||||
}
|
||||
|
||||
- (RecentsDataSource*)recentsDataSource
|
||||
{
|
||||
RecentsDataSource* recentsDataSource = nil;
|
||||
|
||||
if ([self.dataSource isKindOfClass:[RecentsDataSource class]])
|
||||
{
|
||||
recentsDataSource = (RecentsDataSource*)self.dataSource;
|
||||
}
|
||||
|
||||
return recentsDataSource;
|
||||
}
|
||||
|
||||
#pragma mark - MXKDataSourceDelegate
|
||||
|
||||
- (Class<MXKCellRendering>)cellViewClassForCellData:(MXKCellData*)cellData
|
||||
|
@ -1783,73 +1797,58 @@
|
|||
|
||||
- (void)joinARoom
|
||||
{
|
||||
[currentAlert dismissViewControllerAnimated:NO completion:nil];
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
|
||||
// Prompt the user to type a room id or room alias
|
||||
currentAlert = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"room_recents_join_room_title", @"Vector", nil)
|
||||
message:NSLocalizedStringFromTable(@"room_recents_join_room_prompt", @"Vector", nil)
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
[currentAlert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
|
||||
|
||||
textField.secureTextEntry = NO;
|
||||
textField.placeholder = nil;
|
||||
textField.keyboardType = UIKeyboardTypeDefault;
|
||||
}];
|
||||
|
||||
[currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"]
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction * action) {
|
||||
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
self->currentAlert = nil;
|
||||
}
|
||||
|
||||
}]];
|
||||
|
||||
[currentAlert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"join", @"Vector", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
|
||||
NSString *roomAliasOrId = [self->currentAlert textFields].firstObject.text;
|
||||
|
||||
self->currentAlert = nil;
|
||||
|
||||
[self.activityIndicator startAnimating];
|
||||
[self showRoomDirectory];
|
||||
}
|
||||
|
||||
// TODO
|
||||
self->currentRequest = [self.mainSession joinRoom:roomAliasOrId viaServers:nil success:^(MXRoom *room) {
|
||||
|
||||
self->currentRequest = nil;
|
||||
[self.activityIndicator stopAnimating];
|
||||
|
||||
// Show the room
|
||||
[[AppDelegate theDelegate] showRoom:room.roomId andEventId:nil withMatrixSession:self.mainSession];
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
|
||||
NSLog(@"[RecentsViewController] Join joinARoom (%@) failed", roomAliasOrId);
|
||||
|
||||
self->currentRequest = nil;
|
||||
[self.activityIndicator stopAnimating];
|
||||
|
||||
// Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
}
|
||||
|
||||
}]];
|
||||
- (void)showRoomDirectory
|
||||
{
|
||||
if (!self.self.mainSession)
|
||||
{
|
||||
NSLog(@"[RecentsViewController] Fail to show room directory, session is nil");
|
||||
return;
|
||||
}
|
||||
|
||||
[currentAlert mxk_setAccessibilityIdentifier:@"RecentsVCJoinARoomAlert"];
|
||||
[self presentViewController:currentAlert animated:YES completion:nil];
|
||||
self.roomsDirectoryCoordinatorBridgePresenter = [[RoomsDirectoryCoordinatorBridgePresenter alloc] initWithSession:self.mainSession dataSource:[self.recentsDataSource.publicRoomsDirectoryDataSource copy]];
|
||||
self.roomsDirectoryCoordinatorBridgePresenter.delegate = self;
|
||||
[self.roomsDirectoryCoordinatorBridgePresenter presentFrom:self animated:YES];
|
||||
}
|
||||
|
||||
- (void)openPublicRoom:(MXPublicRoom *)publicRoom
|
||||
{
|
||||
if (!self.recentsDataSource)
|
||||
{
|
||||
NSLog(@"[RecentsViewController] Fail to open public room, dataSource is not kind of class MXKRecentsDataSource");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check whether the user has already joined the selected public room
|
||||
if ([self.recentsDataSource.publicRoomsDirectoryDataSource.mxSession roomWithRoomId:publicRoom.roomId])
|
||||
{
|
||||
// Open the public room
|
||||
[[AppDelegate theDelegate] showRoom:publicRoom.roomId andEventId:nil withMatrixSession:self.recentsDataSource.publicRoomsDirectoryDataSource.mxSession restoreInitialDisplay:NO];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Preview the public room
|
||||
if (publicRoom.worldReadable)
|
||||
{
|
||||
RoomPreviewData *roomPreviewData = [[RoomPreviewData alloc] initWithPublicRoom:publicRoom andSession:self.recentsDataSource.publicRoomsDirectoryDataSource.mxSession];
|
||||
|
||||
[self startActivityIndicator];
|
||||
|
||||
// Try to get more information about the room before opening its preview
|
||||
[roomPreviewData peekInRoom:^(BOOL succeeded) {
|
||||
[self stopActivityIndicator];
|
||||
|
||||
[[AppDelegate theDelegate].masterTabBarController showRoomPreview:roomPreviewData];
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
RoomPreviewData *roomPreviewData = [[RoomPreviewData alloc] initWithPublicRoom:publicRoom andSession:self.recentsDataSource.publicRoomsDirectoryDataSource.mxSession];
|
||||
[[AppDelegate theDelegate].masterTabBarController showRoomPreview:roomPreviewData];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Table view scrolling
|
||||
|
@ -2052,4 +2051,28 @@
|
|||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark - RoomsDirectoryCoordinatorBridgePresenterDelegate
|
||||
|
||||
- (void)roomsDirectoryCoordinatorBridgePresenterDelegateDidComplete:(RoomsDirectoryCoordinatorBridgePresenter *)coordinatorBridgePresenter
|
||||
{
|
||||
[coordinatorBridgePresenter dismissWithAnimated:YES completion:nil];
|
||||
self.roomsDirectoryCoordinatorBridgePresenter = nil;
|
||||
}
|
||||
|
||||
- (void)roomsDirectoryCoordinatorBridgePresenterDelegate:(RoomsDirectoryCoordinatorBridgePresenter *)coordinatorBridgePresenter didSelectRoom:(MXPublicRoom *)room
|
||||
{
|
||||
[coordinatorBridgePresenter dismissWithAnimated:YES completion:^{
|
||||
[self openPublicRoom:room];
|
||||
}];
|
||||
self.roomsDirectoryCoordinatorBridgePresenter = nil;
|
||||
}
|
||||
|
||||
- (void)roomsDirectoryCoordinatorBridgePresenterDelegateDidTapCreateNewRoom:(RoomsDirectoryCoordinatorBridgePresenter *)coordinatorBridgePresenter
|
||||
{
|
||||
[coordinatorBridgePresenter dismissWithAnimated:YES completion:^{
|
||||
[self createNewRoom];
|
||||
}];
|
||||
self.roomsDirectoryCoordinatorBridgePresenter = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#import "Riot-Swift.h"
|
||||
|
||||
@interface RoomsViewController ()<RoomsDirectoryCoordinatorBridgePresenterDelegate>
|
||||
@interface RoomsViewController ()
|
||||
{
|
||||
RecentsDataSource *recentsDataSource;
|
||||
|
||||
|
@ -30,8 +30,6 @@
|
|||
UIView* footerSpinnerView;
|
||||
}
|
||||
|
||||
@property (nonatomic, strong) RoomsDirectoryCoordinatorBridgePresenter *roomsDirectoryCoordinatorBridgePresenter;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RoomsViewController
|
||||
|
@ -128,9 +126,7 @@
|
|||
|
||||
- (void)onPlusButtonPressed
|
||||
{
|
||||
self.roomsDirectoryCoordinatorBridgePresenter = [[RoomsDirectoryCoordinatorBridgePresenter alloc] initWithSession:self.mainSession dataSource:[recentsDataSource.publicRoomsDirectoryDataSource copy]];
|
||||
self.roomsDirectoryCoordinatorBridgePresenter.delegate = self;
|
||||
[self.roomsDirectoryCoordinatorBridgePresenter presentFrom:self animated:YES];
|
||||
[self showRoomDirectory];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
@ -263,38 +259,6 @@
|
|||
[self openPublicRoom:publicRoom];
|
||||
}
|
||||
|
||||
- (void)openPublicRoom:(MXPublicRoom *)publicRoom
|
||||
{
|
||||
// Check whether the user has already joined the selected public room
|
||||
if ([recentsDataSource.publicRoomsDirectoryDataSource.mxSession roomWithRoomId:publicRoom.roomId])
|
||||
{
|
||||
// Open the public room
|
||||
[[AppDelegate theDelegate] showRoom:publicRoom.roomId andEventId:nil withMatrixSession:recentsDataSource.publicRoomsDirectoryDataSource.mxSession restoreInitialDisplay:NO];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Preview the public room
|
||||
if (publicRoom.worldReadable)
|
||||
{
|
||||
RoomPreviewData *roomPreviewData = [[RoomPreviewData alloc] initWithPublicRoom:publicRoom andSession:recentsDataSource.publicRoomsDirectoryDataSource.mxSession];
|
||||
|
||||
[self startActivityIndicator];
|
||||
|
||||
// Try to get more information about the room before opening its preview
|
||||
[roomPreviewData peekInRoom:^(BOOL succeeded) {
|
||||
[self stopActivityIndicator];
|
||||
|
||||
[[AppDelegate theDelegate].masterTabBarController showRoomPreview:roomPreviewData];
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
RoomPreviewData *roomPreviewData = [[RoomPreviewData alloc] initWithPublicRoom:publicRoom andSession:recentsDataSource.publicRoomsDirectoryDataSource.mxSession];
|
||||
[[AppDelegate theDelegate].masterTabBarController showRoomPreview:roomPreviewData];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)triggerDirectoryPagination
|
||||
{
|
||||
if (!recentsDataSource
|
||||
|
@ -351,30 +315,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
#pragma mark - RoomsDirectoryCoordinatorBridgePresenterDelegate
|
||||
|
||||
- (void)roomsDirectoryCoordinatorBridgePresenterDelegateDidComplete:(RoomsDirectoryCoordinatorBridgePresenter *)coordinatorBridgePresenter
|
||||
{
|
||||
[coordinatorBridgePresenter dismissWithAnimated:YES completion:nil];
|
||||
self.roomsDirectoryCoordinatorBridgePresenter = nil;
|
||||
}
|
||||
|
||||
- (void)roomsDirectoryCoordinatorBridgePresenterDelegate:(RoomsDirectoryCoordinatorBridgePresenter *)coordinatorBridgePresenter didSelectRoom:(MXPublicRoom *)room
|
||||
{
|
||||
[coordinatorBridgePresenter dismissWithAnimated:YES completion:^{
|
||||
[self openPublicRoom:room];
|
||||
}];
|
||||
self.roomsDirectoryCoordinatorBridgePresenter = nil;
|
||||
}
|
||||
|
||||
- (void)roomsDirectoryCoordinatorBridgePresenterDelegateDidTapCreateNewRoom:(RoomsDirectoryCoordinatorBridgePresenter *)coordinatorBridgePresenter
|
||||
{
|
||||
[coordinatorBridgePresenter dismissWithAnimated:YES completion:^{
|
||||
[self createNewRoom];
|
||||
}];
|
||||
self.roomsDirectoryCoordinatorBridgePresenter = nil;
|
||||
}
|
||||
|
||||
#pragma mark - Empty view management
|
||||
|
||||
- (void)updateEmptyView
|
||||
|
|
|
@ -48,6 +48,7 @@ targets:
|
|||
- path: ../Riot/Modules/SetPinCode/SetupBiometrics/BiometricsAuthenticationPresenter.swift
|
||||
- path: ../Riot/Categories/UNUserNotificationCenter.swift
|
||||
- path: ../Riot/Managers/KeyValueStorage/KeyValueStore.swift
|
||||
- path: ../Riot/Managers/EncryptionKeyManager/EncryptionKeyManager.swift
|
||||
- path: ../Riot/Categories/Bundle.swift
|
||||
- path: ../Riot/Generated/Strings.swift
|
||||
- path: ../Riot/Generated/Images.swift
|
||||
|
|
|
@ -49,6 +49,8 @@ targets:
|
|||
- path: ../Config/CommonConfiguration.swift
|
||||
- path: ../Riot/Utils/UserNameColorGenerator.swift
|
||||
- path: ../Riot/Categories/MXRoomSummary+Riot.m
|
||||
- path: ../Riot/Managers/EncryptionKeyManager/EncryptionKeyManager.swift
|
||||
- path: ../Riot/Managers/KeyValueStorage
|
||||
- path: ../Riot/Managers/Settings/RiotSettings.swift
|
||||
- path: ../Riot/Categories/UIColor.swift
|
||||
- path: ../Riot/Categories/UISearchBar.swift
|
||||
|
|
|
@ -46,3 +46,5 @@ targets:
|
|||
- path: ../Config/BuildSettings.swift
|
||||
- path: ../Config/Configurable.swift
|
||||
- path: ../Riot/Managers/Settings/RiotSettings.swift
|
||||
- path: ../Riot/Managers/EncryptionKeyManager/EncryptionKeyManager.swift
|
||||
- path: ../Riot/Managers/KeyValueStorage
|
||||
|
|
|
@ -274,8 +274,9 @@ platform :ios do
|
|||
private_lane :update_build_number do |options|
|
||||
build_number = options[:build_number]
|
||||
|
||||
increment_build_number_in_xcodeproj(
|
||||
build_number: build_number,
|
||||
update_file_content(
|
||||
"../Config/AppIdentifiers.xcconfig",
|
||||
/(CURRENT_PROJECT_VERSION\s*=)\s*.*/ => "\\1 #{build_number}"
|
||||
)
|
||||
end
|
||||
|
||||
|
@ -336,3 +337,16 @@ platform :ios do
|
|||
.last # Latest ref found, in "version:refname" semantic order
|
||||
end
|
||||
end
|
||||
|
||||
# Update an arbitrary file by applying some RegExp replacements to its content
|
||||
#
|
||||
# @param [String] file The path to the file that needs replacing
|
||||
# @param [Hash<RegExp, String>] replacements A list of replacements to apply
|
||||
#
|
||||
def update_file_content(file, replacements)
|
||||
content = File.read(file)
|
||||
replacements.each do |pattern, replacement|
|
||||
content.gsub!(pattern, replacement)
|
||||
end
|
||||
File.write(file, content)
|
||||
end
|
Loading…
Reference in a new issue