diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index a9e8845e4..0140524ea 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,8 +1,7 @@ ### Pull Request Checklist - - -* [ ] UI change has been tested on both light and dark themes +* [ ] I read the [contributing guide](https://github.com/vector-im/element-ios/blob/develop/CONTRIBUTING.md) +* [ ] UI change has been tested on both light and dark themes, in portrait and landscape orientations and on iPhone and iPad simulators * [ ] Pull request is based on the develop branch * [ ] Pull request updates [CHANGES.rst](https://github.com/vector-im/riot-ios/blob/develop/CHANGES.rst) * [ ] Pull request includes screenshots or videos of UI changes diff --git a/.gitignore b/.gitignore index e41887ec5..01164a0af 100644 --- a/.gitignore +++ b/.gitignore @@ -33,5 +33,7 @@ Pods/ fastlane/report.xml fastlane/Reports fastlane/README.md +fastlane/Preview.html +fastlane/metadata/ provisioning_profiles/ diff --git a/CHANGES.rst b/CHANGES.rst index 6ce006cff..aa8287e8b 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,39 @@ +Changes in 1.0.6 (2020-08-26) +================================================= + +Features: + * + +Improvements: + * Upgrade MatrixKit version ([v0.12.15](https://github.com/matrix-org/matrix-ios-kit/releases/tag/v0.12.15)). + * Config fixes. + * Introduce TableViewSections. Refactor RoomSettingsViewController & SettingsViewController. + * AuthenticationVC: Make forgot password button and phone number text field configurable. + * Introduce httpAdditionalHeaders in BuildSettings. + +Bugfix: + * Fix biometry name null case (#3551). + * Avoid email validation link to redirect to web app (#3513). + * Wait for first sync complete before stopping loading screen (#3336). + * Disable key backup on extensions (#3371). + * Gracefully cancel verification on iOS 13 drag gesture (#3556). + +API Change: + * + +Translations: + * + +Others: + * Ignore fastlane/Preview.html + * SonarCloud: Fix some code smells. + +Build: + * + +Test: + * + Changes in 1.0.5 (2020-08-13) ================================================= diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..cc28bc49d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,33 @@ +# Contributing code to Matrix + +Please read Synapse [contributing guide](https://github.com/matrix-org/synapse/blob/master/CONTRIBUTING.md). + +# Contributing code to Element iOS + +## I want to help translating + +If you want to fix an issue for an English string, please submit a pull request to the Element iOS GitHub repository. +If you want to fix an issue for another language, add a missing translation, or add a new language, please read [Element Web translating guide](https://github.com/vector-im/element-web/blob/develop/docs/translating.md) first and then use the Element iOS [Weblate](https://translate.riot.im/projects/riot-ios/). + +If you have any question regarding translations please ask in [Element Translation room](https://matrix.to/#/#element-translations:matrix.org). + +## Setting up a development environment + +Please refer to the [installation guide](INSTALL.md) to setup the project. + +## Implement a new screen or new screen flow + +New screen flows are currently using MVVM-Coordinator pattern. Please refer to the screen template [Readme](Tools/Templates/README.md) to create a new screen or a new screen flow. + +## Coding style + +For Swift coding style we use [SwiftLint](https://github.com/realm/SwiftLint) to check some conventions at compile time (rules are located in the `.swiftlint.yml` file). +Otherwise please have a look to [Apple Swift conventions](https://swift.org/documentation/api-design-guidelines.html#conventions). We are also using some of the conventions of [raywenderlich.com Swift style guide](https://github.com/raywenderlich/swift-style-guide). + +## Pull request + +When you are making a pull request please read carefully the [Pull Request Checklist](https://github.com/vector-im/element-ios/blob/develop/.github/PULL_REQUEST_TEMPLATE.md). + +## Thanks + +Thanks for contributing to Matrix projects! \ No newline at end of file diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index 117d3f6d2..000000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,4 +0,0 @@ -Contributing code to Riot iOS -================================== - -riot-ios follows the same pattern as https://github.com/matrix-org/synapse/blob/master/CONTRIBUTING.md diff --git a/Config/AppConfiguration.swift b/Config/AppConfiguration.swift index 924c8a49c..f438024cf 100644 --- a/Config/AppConfiguration.swift +++ b/Config/AppConfiguration.swift @@ -36,6 +36,9 @@ class AppConfiguration: CommonConfiguration { // Each room member will be considered as a potential contact. MXKContactManager.shared().contactManagerMXRoomSource = MXKContactManagerMXRoomSource.all + + // Enable key backup on app + MXSDKOptions.sharedInstance().enableKeyBackupWhenStartingMXCrypto = true } diff --git a/Config/BuildSettings.swift b/Config/BuildSettings.swift index 3e26922f3..a23f58825 100644 --- a/Config/BuildSettings.swift +++ b/Config/BuildSettings.swift @@ -166,7 +166,7 @@ final class BuildSettings: NSObject { static let allowLocalContactsAccess: Bool = true - // MARK: - Screen settings - + // MARK: - General Settings Screen static let settingsScreenShowUserFirstName: Bool = false static let settingsScreenShowUserSurname: Bool = false @@ -182,13 +182,31 @@ final class BuildSettings: NSObject { static let settingsScreenAllowBugReportingManually: Bool = true static let settingsScreenAllowDeactivatingAccount: Bool = true + // MARK: - Room Settings Screen + + static let roomSettingsScreenShowLowPriorityOption: Bool = true + static let roomSettingsScreenShowDirectChatOption: Bool = true + static let roomSettingsScreenAllowChangingAccessSettings: Bool = true + static let roomSettingsScreenAllowChangingHistorySettings: Bool = true + static let roomSettingsScreenShowAddressSettings: Bool = true + static let roomSettingsScreenShowFlairSettings: Bool = true + static let roomSettingsScreenShowAdvancedSettings: Bool = true + // MARK: - Message static let messageDetailsAllowShare: Bool = true static let messageDetailsAllowPermalink: Bool = true static let messageDetailsAllowViewSource: Bool = true + static let messageDetailsAllowSave: Bool = true + + // MARK: - HTTP + /// Additional HTTP headers will be sent by all requests. Not recommended to use request-specific headers, like `Authorization`. + /// Empty dictionary by default. + static let httpAdditionalHeaders: [String: String] = [:] // MARK: - Authentication Screen static let authScreenShowRegister = true + static let authScreenShowPhoneNumber = true + static let authScreenShowForgotPassword = true static let authScreenShowCustomServerOptions = true } diff --git a/Config/CommonConfiguration.swift b/Config/CommonConfiguration.swift index 93d7f07cc..bda487650 100644 --- a/Config/CommonConfiguration.swift +++ b/Config/CommonConfiguration.swift @@ -40,6 +40,11 @@ class CommonConfiguration: NSObject, Configurable { // Enable lazy loading settings.syncWithLazyLoadOfRoomMembers = true + + settings.messageDetailsAllowSharing = BuildSettings.messageDetailsAllowShare + settings.messageDetailsAllowSaving = BuildSettings.messageDetailsAllowSave + + MXKContactManager.shared().allowLocalContactsAccess = BuildSettings.allowLocalContactsAccess } private func setupMatrixSDKSettings() { @@ -59,6 +64,12 @@ class CommonConfiguration: NSObject, Configurable { // Use UIKit BackgroundTask for handling background tasks in the SDK sdkOptions.backgroundModeHandler = MXUIKitBackgroundModeHandler() + + // Pass httpAdditionalHeaders to the SDK + sdkOptions.httpAdditionalHeaders = BuildSettings.httpAdditionalHeaders + + // Disable key backup on common + sdkOptions.enableKeyBackupWhenStartingMXCrypto = false } diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 000000000..4150f8f23 --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,157 @@ +# Installation + +## Install build tools + +To build Element iOS project you need: + +- Xcode 11.4+. +- [Ruby](https://www.ruby-lang.org/), a dynamic programming language used by several build tools. +- [cmake](https://gitlab.kitware.com/cmake/cmake), used to build [cmark](https://github.com/commonmark/cmark) dependency of [MatrixKit](https://github.com/matrix-org/matrix-ios-kit) pod. +- [CocoaPods](https://cocoapods.org) 1.9.3. Manages library dependencies for Xcode projects. +- [Homebrew](http://brew.sh/) (recommended), is a package manager for macOS that can be used to install cmake. +- [bundler](https://bundler.io/) (optional), is also a dependency manager used to manage build tools dependency (CocoaPods, Fastlane). + +### Install Ruby + +Ruby is required for several build tools like CocoaPods, bundler and fastlane. Ruby is preinstalled on macOS, the system version is sufficient to build the porject tools, it's not required to install the latest version. If you want to install the lastest version of Ruby please check [official instructions](https://www.ruby-lang.org/en/documentation/installation/#homebrew). + +If you do not want to grant the ruby package manager, [RubyGems](https://rubygems.org/), admin privileges and you prefer install gems into your user directory, you can read instructions from the CocoaPods [guide about sudo-less installation](https://guides.cocoapods.org/using/getting-started.html#sudo-less-installation). + +### Install cmake + +There are several ways to install cmake, downloading binary from [official website](https://cmake.org/download/) or using a package manager like [MacPorts](https://ports.macports.org/port/cmake/summary) or [Homebrew](http://brew.sh/). +To keep it up to date, we recommend you to install cmake using [Homebrew](http://brew.sh/): + +``` +brew install cmake +``` + +### Install CocoaPods + +To install CocoaPods you can grab the right version by using `bundler` (recommended) or you can directly install it with RubyGems: + +``` +gem install cocoapods +``` + +In the last case please ensure that you are using the same version as indicated at the end of the `Podfile.lock` file. + +### Install bundler (optional) + +By using `bundler` you will ensure to use the right versions of build tools used to build and deliver the project. You can find dependency definitions in the `Gemfile`. To install `bundler`: + +``` +gem install bundler +``` + +## Choose Matrix SDKs version to build + +To choose the [MatrixKit](https://github.com/matrix-org/matrix-ios-kit) version (and depending MatrixSDK and OLMKit) you want to develop and build against you will have to modify the right definitions of `$matrixKitVersion` variable in the `Podfile`. + +### Determine your needs + +To select which `$matrixKitVersion` value to use you have to determine your needs: + +- **Build an App Store release version** + +To build the last published App Store code you just need to checkout master branch. If you want to build an older App Store version just checkout the tag of the corresponding version. You have nothing to modify in the `Podfile`. In this case `$matrixKitVersion` will be set to a specific version of the MatrixKit already published on CocoaPods repository. + +- **Build last development code and modify Element project only** + +If you want to build last development code you have to checkout the develop branch and use `$matrixKitVersion = {'develop' => 'develop'}` in the `Podfile`. This will also use MatrixKit and MatrixSDK develop branches. + +- **Build specific branch of Kit and SDK and modify Element project only** + +If you want to build a specific branch for the MatrixKit and the MatrixSDK you have to indicate them using a dictionary like this: `$matrixKitVersion = {'kit branch name' => 'sdk branch name'}`. + +- **Build any branch and be able to modify MatrixKit and MatrixSDK locally** + +If you want to modify MatrixKit and/or MatrixSDK locally and see the result in Element project you have to uncommment `$matrixKitVersion = :local` in the `Podfile`. +But before you have to checkout [MatrixKit](https://github.com/matrix-org/matrix-ios-kit) repository in `../matrix-ios-kit` and [MatrixSDK](https://github.com/matrix-org/matrix-ios-sdk) in `../matrix-ios-sdk` locally relatively to your Element iOS project folder. +Be sure to use compatible branches for Element iOS, MatrixKit and MatrixSDK. For example if you want to modify Element iOS from develop branch use MatrixKit and MatrixSDK develop branches and then make your modifications. + +**Important**: By working with local pods (development pods) you will need to use legacy build system in Xcode, to have your local changes taken into account. To enable it go to Xcode menu and select `File > Workspace Settings… > Build System` and then choose `Legacy Build System`. + +### Modify `$matrixKitVersion` after installation of dependencies + +Assuming you have already completed the **Install dependencies** instructions from **Build** section below. + +Each time you edit `$matrixKitVersion` variable in the `Podfile` you will have to run the `pod install` command. + +## Build + +### Install dependencies + +Before opening the Element Xcode workspace, you need to install dependencies via CocoaPods. + +To be sure to use the right CocoaPods version you can use `bundler`: + +``` +$ cd Riot +$ bundle install +$ bundle exec pod install +``` + +Or if you prefer to use directly CocoaPods: + +``` +$ cd Riot +$ pod install +``` + +This will load all dependencies for the Element source code, including [MatrixKit](https://github.com/matrix-org/matrix-ios-kit) +and [MatrixSDK](https://github.com/matrix-org/matrix-ios-sdk). + +### Open workspace + +Then, open `Riot.xcworkspace` with Xcode. + +``` +$ open Riot.xcworkspace +``` + +**Note**: If you have multiple Xcode versions installed don't forget to use the right version of Command Line Tools when you are building the app. To check the Command Line Tools version go to `Xcode > Preferences > Locations > Command Line Tools` and check that the displayed version match your Xcode version. + +### Configure project + +You may need to change the bundle identifier and app group identifier to be unique to get Xcode to build the app. Make sure to change the bundle identifier, application group identifier and app name in the `Config/Common.xcconfig` file to your new identifiers. + +## Generate IPA + +To build the IPA we are currently using [fastlane](https://fastlane.tools/). + +**Set your project informations** + +Before making the release you need to modify the `fastlane/.env.default` file and set all your project informations like your App ID, Team ID, certificate names and so on. + +**Install or update build tools** + +The preferred way to use the fastlane script is to use `bundler`, to be sure to use the right dependency versions. + +After opening the terminal in the project root folder. The first time you perform a release you need to run: + +`bundle install` + +For other times: + +`bundle update` + +**Run fastlane script** + +Before executing the release command you need to export your Apple ID in environment variables: + +`export APPLE_ID="foo.bar@apple.com"` + +To make an App Store release you can directly execute this command: + +`bundle exec fastlane app_store build_number:` + +Or you can use the wrapper script located at `/Tools/Release/buildRelease.sh`. For that go to the `Release` folder: + +`$ cd ./Tools/Release/` + +And then indicate a branch or a tag like this: + +`$ ./buildRelease.sh ` + + diff --git a/Podfile b/Podfile index b153caf8c..509beffd3 100644 --- a/Podfile +++ b/Podfile @@ -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.12' +$matrixKitVersion = '= 0.12.15' # $matrixKitVersion = :local # $matrixKitVersion = {'develop' => 'develop'} diff --git a/Podfile.lock b/Podfile.lock index a20c130a3..93a9c2e5e 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -16,27 +16,27 @@ PODS: - AFNetworking/NSURLSession - cmark (0.24.1) - DGCollectionViewLeftAlignFlowLayout (1.0.4) - - DTCoreText (1.6.24): - - DTCoreText/Core (= 1.6.24) + - DTCoreText (1.6.25): + - DTCoreText/Core (= 1.6.25) - DTFoundation/Core (~> 1.7.5) - DTFoundation/DTAnimatedGIF (~> 1.7.5) - DTFoundation/DTHTMLParser (~> 1.7.5) - DTFoundation/UIKit (~> 1.7.5) - - DTCoreText/Core (1.6.24): + - DTCoreText/Core (1.6.25): - DTFoundation/Core (~> 1.7.5) - DTFoundation/DTAnimatedGIF (~> 1.7.5) - DTFoundation/DTHTMLParser (~> 1.7.5) - DTFoundation/UIKit (~> 1.7.5) - - DTCoreText/Extension (1.6.24): + - DTCoreText/Extension (1.6.25): - DTFoundation/Core (~> 1.7.5) - DTFoundation/DTAnimatedGIF (~> 1.7.5) - DTFoundation/DTHTMLParser (~> 1.7.5) - DTFoundation/UIKit (~> 1.7.5) - - DTFoundation/Core (1.7.14) - - DTFoundation/DTAnimatedGIF (1.7.14) - - DTFoundation/DTHTMLParser (1.7.14): + - DTFoundation/Core (1.7.15) + - DTFoundation/DTAnimatedGIF (1.7.15) + - DTFoundation/DTHTMLParser (1.7.15): - DTFoundation/Core - - DTFoundation/UIKit (1.7.14): + - DTFoundation/UIKit (1.7.15): - DTFoundation/Core - FlowCommoniOS (1.8.7) - GBDeviceInfo (6.3.0): @@ -52,38 +52,38 @@ PODS: - MatomoTracker (7.2.1): - MatomoTracker/Core (= 7.2.1) - MatomoTracker/Core (7.2.1) - - MatrixKit (0.12.12): + - MatrixKit (0.12.15): - cmark (~> 0.24.1) - DTCoreText (~> 1.6.23) - HPGrowingTextView (~> 1.1) - libPhoneNumber-iOS (~> 0.9.13) - - MatrixKit/Core (= 0.12.12) - - MatrixSDK (= 0.16.11) - - MatrixKit/AppExtension (0.12.12): + - MatrixKit/Core (= 0.12.15) + - MatrixSDK (= 0.16.13) + - MatrixKit/AppExtension (0.12.15): - cmark (~> 0.24.1) - DTCoreText (~> 1.6.23) - DTCoreText/Extension - HPGrowingTextView (~> 1.1) - libPhoneNumber-iOS (~> 0.9.13) - - MatrixSDK (= 0.16.11) - - MatrixKit/Core (0.12.12): + - MatrixSDK (= 0.16.13) + - MatrixKit/Core (0.12.15): - cmark (~> 0.24.1) - DTCoreText (~> 1.6.23) - HPGrowingTextView (~> 1.1) - libPhoneNumber-iOS (~> 0.9.13) - - MatrixSDK (= 0.16.11) - - MatrixSDK (0.16.11): - - MatrixSDK/Core (= 0.16.11) - - MatrixSDK/Core (0.16.11): + - MatrixSDK (= 0.16.13) + - MatrixSDK (0.16.13): + - MatrixSDK/Core (= 0.16.13) + - MatrixSDK/Core (0.16.13): - AFNetworking (~> 4.0.0) - GZIP (~> 1.2.2) - libbase58 (~> 0.1.4) - OLMKit (~> 3.1.0) - Realm (~> 4.4.0) - - MatrixSDK/JingleCallStack (0.16.11): + - MatrixSDK/JingleCallStack (0.16.13): - JitsiMeetSDK (~> 2.8.1) - MatrixSDK/Core - - MatrixSDK/SwiftSupport (0.16.11): + - MatrixSDK/SwiftSupport (0.16.13): - MatrixSDK/Core - OLMKit (3.1.0): - OLMKit/olmc (= 3.1.0) @@ -113,8 +113,8 @@ DEPENDENCIES: - KeychainAccess (~> 4.2) - KTCenterFlowLayout (~> 1.3.1) - MatomoTracker (~> 7.2.0) - - MatrixKit (= 0.12.12) - - MatrixKit/AppExtension (= 0.12.12) + - MatrixKit (= 0.12.15) + - MatrixKit/AppExtension (= 0.12.15) - MatrixSDK - MatrixSDK/JingleCallStack - MatrixSDK/SwiftSupport @@ -156,8 +156,8 @@ SPEC CHECKSUMS: AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce cmark: 1d9ad0375e3b9fa281732e992467903606015520 DGCollectionViewLeftAlignFlowLayout: a0fa58797373ded039cafba8133e79373d048399 - DTCoreText: 0298d372ccc137e51f27b3ec1af65fd4af5d173a - DTFoundation: 25aa19bb7c6e225b1dfae195604fb8cf1da0ab4c + DTCoreText: e92f4cf6b36d9d71ce4436d12cf089d74ab0596b + DTFoundation: 767ca882209ef4d5132ec7e702526d5ed5bb71a2 FlowCommoniOS: 1647a1775b988f5d97202f635bcbcbce4f4c46a1 GBDeviceInfo: a3f39dba1a04dcb630abff65d6f7e8fbf319eadd GZIP: af5c90ef903776a7e9afe6ebebd794a84a2929d4 @@ -168,8 +168,8 @@ SPEC CHECKSUMS: libbase58: 7c040313537b8c44b6e2d15586af8e21f7354efd libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75 MatomoTracker: 246b6b0693cf39b356134dec7561f719d3538b96 - MatrixKit: cb92677c837ca56448a2f938717c9be6c7d03973 - MatrixSDK: 021fe99187eb3eb6999997039bcdcfcacb8b50aa + MatrixKit: 0fcc9a131a120637d7da37db2e02ab22241f171d + MatrixSDK: f96afe337d5a408c33a4a67a198afaf5cade56e7 OLMKit: 4ee0159d63feeb86d836fdcfefe418e163511639 Realm: 4eb04d7487bd43c0581256f40b424eafb711deff Reusable: 53a9acf5c536f229b31b5865782414b508252ddb @@ -178,6 +178,6 @@ SPEC CHECKSUMS: zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: c9fbf64577fd39d125dfea51f638685bde771786 +PODFILE CHECKSUM: 4b6b00d796458412d40d8a1e776fd1ce8de97631 COCOAPODS: 1.9.3 diff --git a/README.md b/README.md new file mode 100644 index 000000000..4baaabcf1 --- /dev/null +++ b/README.md @@ -0,0 +1,51 @@ +# Element iOS + +![GitHub release (latest by date)](https://img.shields.io/github/v/release/vector-im/element-ios) +![badge-languages](https://img.shields.io/badge/languages-Swift%20%7C%20ObjC-orange.svg) +[![Swift 5.x](https://img.shields.io/badge/Swift-5.x-orange)](https://developer.apple.com/swift) +[![Build status](https://badge.buildkite.com/cc8f93e32da93fa7c1172398bd8af66254490567c7195a5f3f.svg?branch=develop)](https://buildkite.com/matrix-dot-org/element-ios/builds?branch=develop) +[![Weblate](https://translate.riot.im/widgets/riot-ios/-/svg-badge.svg)](https://translate.riot.im/engage/riot-ios/?utm_source=widget) +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=im.vector.app.ios&metric=alert_status)](https://sonarcloud.io/dashboard?id=im.vector.app.ios) +[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=im.vector.app.ios&metric=bugs)](https://sonarcloud.io/dashboard?id=im.vector.app.ios) +[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=im.vector.app.ios&metric=vulnerabilities)](https://sonarcloud.io/dashboard?id=im.vector.app.ios) +[![Element iOS Matrix room #element-ios:matrix.org](https://img.shields.io/matrix/element-ios:matrix.org.svg?label=%23element-ios:matrix.org&logo=matrix&server_fqdn=matrix.org)](https://matrix.to/#/#element-ios:matrix.org) +![GitHub](https://img.shields.io/github/license/vector-im/element-ios) +[![Twitter URL](https://img.shields.io/twitter/url?label=Element&url=https%3A%2F%2Ftwitter.com%2Felement_hq)](https://twitter.com/element_hq) + +Element iOS is an iOS [Matrix](https://matrix.org/) client provided by [Element](https://element.io/). It is based on [MatrixKit](https://github.com/matrix-org/matrix-ios-kit) and [MatrixSDK](https://github.com/matrix-org/matrix-ios-sdk). + +

+ + Download on the app store + +

+ +## Beta testing + +You can try last beta build by accessing our [TestFlight Public Link](https://testflight.apple.com/join/lCeTuDKM). For questions and feedback about latest TestFlight build, please access the Element iOS Matrix room: [#element-ios:matrix.org](https://matrix.to/#/#element-ios:matrix.org). + +## Build instructions + +To build the application please refer to the [installation guide](./INSTALL.md). + +## Contributing + +If you want to contribute to Element iOS code or translations please refer to the [contribution guide](CONTRIBUTING.md). + +## Support + +When you are experiencing an issue on Element iOS, please first search in [GitHub issues](https://github.com/vector-im/element-ios/issues) +and then in [#element-ios:matrix.org](https://matrix.to/#/#element-ios:matrix.org). +If after your research you still have a question, ask at [#element-ios:matrix.org](https://matrix.to/#/#element-ios:matrix.org). Otherwise feel free to create a GitHub issue if you encounter a bug or a crash, by explaining clearly in detail what happened. You can also perform bug reporting (Rageshake) from the Element application by shaking your phone or going to the application settings. This is especially recommended when you encounter a crash. + +## Copyright & License + +Copyright (c) 2014-2017 OpenMarket Ltd +Copyright (c) 2017 Vector Creations Ltd +Copyright (c) 2017-2020 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. You may obtain a copy of the License in the [LICENSE](LICENSE) file, or at: + +[http://www.apache.org/licenses/LICENSE-2.0](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. diff --git a/README.rst b/README.rst deleted file mode 100644 index e0da5d35f..000000000 --- a/README.rst +++ /dev/null @@ -1,53 +0,0 @@ -Element iOS -========== - -.. image:: https://img.shields.io/matrix/element-ios:matrix.org.svg?label=%23element-ios:matrix.org - :alt: #element-ios:matrix.org - :target: https://matrix.to/#/#element-ios:matrix.org - -Element iOS is an iOS Matrix client. - -.. image:: https://linkmaker.itunes.apple.com/images/badges/en-us/badge_appstore-lrg.svg - :target: https://itunes.apple.com/us/app/element/id1083446067?mt=8 - -It is based on MatrixKit (https://github.com/matrix-org/matrix-ios-kit) and MatrixSDK (https://github.com/matrix-org/matrix-ios-sdk). - -You can build the app from source as per below: - -Build instructions -================== - -Before opening the Element Xcode workspace, you need to build it with the -CocoaPods command:: - - $ cd Element - $ bundle install - $ bundle exec pod install - -This will load all dependencies for the Element source code, including MatrixKit -and MatrixSDK. You will need an recent and updated (``pod setup``) install of -CocoaPods. - -Then, open ``Riot.xcworkspace`` with Xcode - - $ open Riot.xcworkspace - -Developing -========== - -Uncomment the right definitions of ``$matrixKitVersion`` for the version you want to develop and build against. For example, if you are trying to build the develop branch, uncomment ``$matrixKitVersion = 'develop'`` and make sure the more specific MatrixKit version is commented out. Once you are done editing the ``Podfile``, run ``pod install``. - -You may need to change the bundle identifier and app group identifier to be unique to get Xcode to build the app. Make sure to change the application group identifier everywhere by running a search for ``group.im.vector`` and changing every spot that identifier is used to your new identifier. - -Copyright & License -================== - -Copyright (c) 2014-2017 OpenMarket Ltd -Copyright (c) 2017 Vector Creations Ltd -Copyright (c) 2017-2019 New Vector Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. You may obtain a copy of the License in the LICENSE file, or 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. diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index 9f9d86f81..23280ed02 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -750,8 +750,6 @@ EC1CA89A24C9C9A200DE9EBF /* SetupBiometricsCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC1CA89224C9C9A200DE9EBF /* SetupBiometricsCoordinatorType.swift */; }; EC1CA89B24C9C9A200DE9EBF /* SetupBiometricsViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC1CA89324C9C9A200DE9EBF /* SetupBiometricsViewState.swift */; }; EC1CA89C24C9C9A200DE9EBF /* SetupBiometricsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC1CA89424C9C9A200DE9EBF /* SetupBiometricsViewModel.swift */; }; - EC1CA8C824D3160100DE9EBF /* Row.m in Sources */ = {isa = PBXBuildFile; fileRef = EC1CA8C724D3160100DE9EBF /* Row.m */; }; - EC1CA8CB24D3168F00DE9EBF /* Section.m in Sources */ = {isa = PBXBuildFile; fileRef = EC1CA8CA24D3168F00DE9EBF /* Section.m */; }; EC1CA8D424D8103400DE9EBF /* App-Common.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = EC1CA8D324D8103400DE9EBF /* App-Common.xcconfig */; }; EC1CA8D624D8108700DE9EBF /* ShareExtension-Common.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = EC1CA8D524D8108700DE9EBF /* ShareExtension-Common.xcconfig */; }; EC1CA8D824D8118400DE9EBF /* SiriIntents-Common.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = EC1CA8D724D8118400DE9EBF /* SiriIntents-Common.xcconfig */; }; @@ -843,10 +841,14 @@ EC85D754247C0F5B002C44C9 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC85D753247C0F5B002C44C9 /* Constants.swift */; }; EC85D755247C0F84002C44C9 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC85D753247C0F5B002C44C9 /* Constants.swift */; }; EC85D757247E700F002C44C9 /* NSEMemoryStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC85D756247E700F002C44C9 /* NSEMemoryStore.swift */; }; - EC9A3EC524E1616900A8CFAE /* PushNotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC9A3EC424E1616900A8CFAE /* PushNotificationManager.swift */; }; - EC9A3EC624E1632C00A8CFAE /* PushNotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC9A3EC424E1616900A8CFAE /* PushNotificationManager.swift */; }; + EC9A3EC524E1616900A8CFAE /* PushNotificationStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC9A3EC424E1616900A8CFAE /* PushNotificationStore.swift */; }; + EC9A3EC624E1632C00A8CFAE /* PushNotificationStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC9A3EC424E1616900A8CFAE /* PushNotificationStore.swift */; }; EC9A3EC724E1634100A8CFAE /* KeyValueStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC1CA87124C823E700DE9EBF /* KeyValueStore.swift */; }; EC9A3EC824E1634800A8CFAE /* KeychainStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC1CA87424C8259700DE9EBF /* KeychainStore.swift */; }; + ECAE7AE524EC0E01002FA813 /* TableViewSections.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECAE7AE424EC0E01002FA813 /* TableViewSections.swift */; }; + ECAE7AE724EC15F7002FA813 /* Section.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECAE7AE624EC15F7002FA813 /* Section.swift */; }; + ECAE7AE924EC1888002FA813 /* Row.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECAE7AE824EC1888002FA813 /* Row.swift */; }; + ECAE7AEE24EFDD1F002FA813 /* MXSessionState.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECAE7AED24EFDD1F002FA813 /* MXSessionState.swift */; }; ECB101302477CFDB00CF8C11 /* UITableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECB1012C2477CFDB00CF8C11 /* UITableView.swift */; }; ECB101312477CFDB00CF8C11 /* UILabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECB1012D2477CFDB00CF8C11 /* UILabel.swift */; }; ECB101322477CFDB00CF8C11 /* UIDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECB1012E2477CFDB00CF8C11 /* UIDevice.swift */; }; @@ -986,7 +988,6 @@ 3267EFB320E379FD00FF1CAA /* CHANGES.rst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CHANGES.rst; sourceTree = ""; }; 3267EFB420E379FD00FF1CAA /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; fileEncoding = 4; path = Podfile; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; 3267EFB520E379FD00FF1CAA /* AUTHORS.rst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AUTHORS.rst; sourceTree = ""; }; - 3267EFB620E379FD00FF1CAA /* README.rst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.rst; sourceTree = ""; }; 3275FD8B21A5A2C500B9C13D /* TermsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TermsView.swift; sourceTree = ""; }; 3281BCF62201FA4200F4A383 /* UIControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIControl.swift; sourceTree = ""; }; 3284A35020A07C210044F922 /* postMessageAPI.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = postMessageAPI.js; sourceTree = ""; }; @@ -1697,6 +1698,7 @@ B1B5598F20EFC5E400210D55 /* DecryptionFailure.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DecryptionFailure.h; sourceTree = ""; }; B1B5599020EFC5E400210D55 /* Analytics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Analytics.h; sourceTree = ""; }; B1B5599120EFC5E400210D55 /* DecryptionFailureTracker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DecryptionFailureTracker.m; sourceTree = ""; }; + B1B7F22824F3F8E900FD567B /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; B1B9194A2118984300FE25B5 /* RoomPredecessorBubbleCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RoomPredecessorBubbleCell.xib; sourceTree = ""; }; B1B9DED922E9B7350065E677 /* SerializationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SerializationService.swift; sourceTree = ""; }; B1B9DEDB22E9B7440065E677 /* SerializationServiceType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SerializationServiceType.swift; sourceTree = ""; }; @@ -1877,10 +1879,6 @@ EC1CA8BB24D1B4BF00DE9EBF /* SiriIntents-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "SiriIntents-Debug.xcconfig"; sourceTree = ""; }; EC1CA8BC24D1B4CF00DE9EBF /* NSE-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "NSE-Debug.xcconfig"; sourceTree = ""; }; EC1CA8BD24D1B4CF00DE9EBF /* NSE-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "NSE-Release.xcconfig"; sourceTree = ""; }; - EC1CA8C624D3160100DE9EBF /* Row.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Row.h; sourceTree = ""; }; - EC1CA8C724D3160100DE9EBF /* Row.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Row.m; sourceTree = ""; }; - EC1CA8C924D3168F00DE9EBF /* Section.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Section.h; sourceTree = ""; }; - EC1CA8CA24D3168F00DE9EBF /* Section.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Section.m; sourceTree = ""; }; EC1CA8D324D8103400DE9EBF /* App-Common.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "App-Common.xcconfig"; sourceTree = ""; }; EC1CA8D524D8108700DE9EBF /* ShareExtension-Common.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "ShareExtension-Common.xcconfig"; sourceTree = ""; }; EC1CA8D724D8118400DE9EBF /* SiriIntents-Common.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "SiriIntents-Common.xcconfig"; sourceTree = ""; }; @@ -1975,7 +1973,11 @@ EC85D750247C0E8F002C44C9 /* UNUserNotificationCenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UNUserNotificationCenter.swift; sourceTree = ""; }; EC85D753247C0F5B002C44C9 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; EC85D756247E700F002C44C9 /* NSEMemoryStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSEMemoryStore.swift; sourceTree = ""; }; - EC9A3EC424E1616900A8CFAE /* PushNotificationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushNotificationManager.swift; sourceTree = ""; }; + EC9A3EC424E1616900A8CFAE /* PushNotificationStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushNotificationStore.swift; sourceTree = ""; }; + ECAE7AE424EC0E01002FA813 /* TableViewSections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewSections.swift; sourceTree = ""; }; + ECAE7AE624EC15F7002FA813 /* Section.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Section.swift; sourceTree = ""; }; + ECAE7AE824EC1888002FA813 /* Row.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Row.swift; sourceTree = ""; }; + ECAE7AED24EFDD1F002FA813 /* MXSessionState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXSessionState.swift; sourceTree = ""; }; ECB1012C2477CFDB00CF8C11 /* UITableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UITableView.swift; sourceTree = ""; }; ECB1012D2477CFDB00CF8C11 /* UILabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UILabel.swift; sourceTree = ""; }; ECB1012E2477CFDB00CF8C11 /* UIDevice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIDevice.swift; sourceTree = ""; }; @@ -3197,7 +3199,6 @@ B1B5567720EE6C4C00210D55 /* Settings */ = { isa = PBXGroup; children = ( - EC1CA8C524D315EA00DE9EBF /* Models */, B1B5567F20EE6C4C00210D55 /* SettingsViewController.h */, B1B5567E20EE6C4C00210D55 /* SettingsViewController.m */, B1B5578120EF564900210D55 /* Views */, @@ -3467,6 +3468,7 @@ B1B556CD20EE6C4C00210D55 /* Common */ = { isa = PBXGroup; children = ( + ECAE7AEA24EC223D002FA813 /* Models */, EC85D7312477DD54002C44C9 /* SectionHeaders */, B183226923F59F3E0035B2E8 /* Buttons */, B1963B3622933B9500CBA17F /* CollectionView */, @@ -4613,17 +4615,6 @@ path = SetupBiometrics; sourceTree = ""; }; - EC1CA8C524D315EA00DE9EBF /* Models */ = { - isa = PBXGroup; - children = ( - EC1CA8C624D3160100DE9EBF /* Row.h */, - EC1CA8C724D3160100DE9EBF /* Row.m */, - EC1CA8C924D3168F00DE9EBF /* Section.h */, - EC1CA8CA24D3168F00DE9EBF /* Section.m */, - ); - path = Models; - sourceTree = ""; - }; EC3B066324AC6ADD000DF9BF /* CrossSigning */ = { isa = PBXGroup; children = ( @@ -4838,7 +4829,7 @@ children = ( EC85D73C2477DDD0002C44C9 /* PushNotificationService.h */, EC85D73D2477DDD0002C44C9 /* PushNotificationService.m */, - EC9A3EC424E1616900A8CFAE /* PushNotificationManager.swift */, + EC9A3EC424E1616900A8CFAE /* PushNotificationStore.swift */, ); path = PushNotification; sourceTree = ""; @@ -4857,6 +4848,16 @@ path = RiotNSE; sourceTree = ""; }; + ECAE7AEA24EC223D002FA813 /* Models */ = { + isa = PBXGroup; + children = ( + ECAE7AE424EC0E01002FA813 /* TableViewSections.swift */, + ECAE7AE624EC15F7002FA813 /* Section.swift */, + ECAE7AE824EC1888002FA813 /* Row.swift */, + ); + path = Models; + sourceTree = ""; + }; F083BB021E7005FD00A9B29C /* RiotTests */ = { isa = PBXGroup; children = ( @@ -4965,6 +4966,7 @@ B1DCC63322E72C1B00625807 /* UISearchBar.swift */, B11291EB238D704C0077B478 /* FloatingPoint.swift */, 32FD757524D2C9BA00BA7B37 /* Bundle.swift */, + ECAE7AED24EFDD1F002FA813 /* MXSessionState.swift */, ); path = Categories; sourceTree = ""; @@ -5015,7 +5017,7 @@ F094A9991B78D8F000B1FBBF = { isa = PBXGroup; children = ( - 3267EFB620E379FD00FF1CAA /* README.rst */, + B1B7F22824F3F8E900FD567B /* README.md */, 3267EFB320E379FD00FF1CAA /* CHANGES.rst */, 3267EFB520E379FD00FF1CAA /* AUTHORS.rst */, 3267EFB420E379FD00FF1CAA /* Podfile */, @@ -5706,7 +5708,7 @@ EC2B4EF224A1EF34005EB739 /* DataProtectionHelper.swift in Sources */, EC85D7462477E5F7002C44C9 /* NotificationService.swift in Sources */, 32FD755424D074C700BA7B37 /* CommonConfiguration.swift in Sources */, - EC9A3EC624E1632C00A8CFAE /* PushNotificationManager.swift in Sources */, + EC9A3EC624E1632C00A8CFAE /* PushNotificationStore.swift in Sources */, 32FD757424D2BEF700BA7B37 /* InfoPlist.swift in Sources */, EC85D752247C0F52002C44C9 /* UNUserNotificationCenter.swift in Sources */, EC9A3EC724E1634100A8CFAE /* KeyValueStore.swift in Sources */, @@ -5898,6 +5900,7 @@ F05927C91FDED836009F2A68 /* MXGroup+Riot.m in Sources */, B1B5594520EF7BD000210D55 /* TableViewCellWithCollectionView.m in Sources */, B1A6C109238828A6002882FD /* SlidingModalPresentationDelegate.swift in Sources */, + ECAE7AEE24EFDD1F002FA813 /* MXSessionState.swift in Sources */, 32DB557722FDADE50016329E /* ServiceTermsModalCoordinator.swift in Sources */, B185145B24B8C98200EE19EA /* MajorUpdateViewController.swift in Sources */, 32DB557922FDADE50016329E /* ServiceTermsModalScreenViewModel.swift in Sources */, @@ -6058,7 +6061,6 @@ B1A6C10D23882D1D002882FD /* SlidingModalPresentationController.swift in Sources */, 32A6001D22C661100042C1D9 /* EditHistoryCoordinatorType.swift in Sources */, F083BDFA1E7009ED00A9B29C /* RoomPreviewData.m in Sources */, - EC1CA8CB24D3168F00DE9EBF /* Section.m in Sources */, B1B557B420EF5AEF00210D55 /* EventDetailsView.m in Sources */, EC85D751247C0E8F002C44C9 /* UNUserNotificationCenter.swift in Sources */, B1BEE73823DF44A60003A4CB /* UserVerificationSessionsStatusViewAction.swift in Sources */, @@ -6083,7 +6085,6 @@ EC711B7624A63B37008F830C /* SecretsSetupRecoveryKeyViewState.swift in Sources */, 32FDC1CD2386CD390084717A /* RiotSettingIntegrationProvisioning.swift in Sources */, B1BEE73523DF44A60003A4CB /* UserVerificationSessionsStatusViewModel.swift in Sources */, - EC1CA8C824D3160100DE9EBF /* Row.m in Sources */, B1B5572020EE6C4D00210D55 /* ContactsTableViewController.m in Sources */, EC85D7142477DCD7002C44C9 /* KeyVerificationScanConfirmationViewState.swift in Sources */, EC711B9124A63B37008F830C /* SecretsRecoveryWithKeyCoordinatorType.swift in Sources */, @@ -6171,7 +6172,7 @@ EC711BA924A63B58008F830C /* SecureBackupSetupCoordinatorBridgePresenter.swift in Sources */, B1B558C720EF768F00210D55 /* RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.m in Sources */, B1B336C5242B933700F95EC4 /* KeyVerificationSelfVerifyStartViewModel.swift in Sources */, - EC9A3EC524E1616900A8CFAE /* PushNotificationManager.swift in Sources */, + EC9A3EC524E1616900A8CFAE /* PushNotificationStore.swift in Sources */, B1B558F020EF768F00210D55 /* RoomOutgoingAttachmentWithPaginationTitleBubbleCell.m in Sources */, 926FA53F1F4C132000F826C2 /* MXSession+Riot.m in Sources */, EC711B8324A63B37008F830C /* SecretsSetupRecoveryPassphraseCoordinator.swift in Sources */, @@ -6224,6 +6225,7 @@ B14084CE23BFA0990010F692 /* KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.swift in Sources */, B14F143222144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyCoordinator.swift in Sources */, B110872621F098F0003554A5 /* ActivityIndicatorView.swift in Sources */, + ECAE7AE924EC1888002FA813 /* Row.swift in Sources */, B1CE83E02422817200D07506 /* KeyVerificationVerifyBySASViewController.swift in Sources */, B19EFA3921F8BB2C00FC070E /* KeyBackupRecoverCoordinatorType.swift in Sources */, B1C3360322F1ED600021BA8D /* MediaPickerCoordinator.swift in Sources */, @@ -6294,6 +6296,7 @@ B125FE1B231D5BF200B72806 /* SettingsDiscoveryTableViewSection.swift in Sources */, B18DEDD5243377C10075FEF7 /* KeyVerificationSelfVerifyWaitViewModel.swift in Sources */, EC711B8B24A63B37008F830C /* SecretsRecoveryWithPassphraseViewState.swift in Sources */, + ECAE7AE524EC0E01002FA813 /* TableViewSections.swift in Sources */, B1CE83DA2422817200D07506 /* KeyVerificationVerifyByScanningViewModel.swift in Sources */, 32242F0921E8B05F00725742 /* UIColor.swift in Sources */, B16932E720F3C37100746532 /* HomeMessagesSearchDataSource.m in Sources */, @@ -6311,6 +6314,7 @@ B1B558FF20EF768F00210D55 /* RoomIncomingTextMsgBubbleCell.m in Sources */, EC85D7342477DD54002C44C9 /* SectionHeaderView.m in Sources */, B1098C0021ECFE65000DDA48 /* KeyBackupSetupPassphraseViewController.swift in Sources */, + ECAE7AE724EC15F7002FA813 /* Section.swift in Sources */, B1B5591020EF782800210D55 /* TableViewCellWithPhoneNumberTextField.m in Sources */, B1CE83E52422817200D07506 /* KeyVerificationVerifyBySASViewModel.swift in Sources */, B1DB4F06223015080065DBFA /* Character.swift in Sources */, @@ -6715,7 +6719,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1.0.5; + CURRENT_PROJECT_VERSION = 1.0.6; DEFINES_MODULE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -6735,7 +6739,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 1.0.5; + MARKETING_VERSION = 1.0.6; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -6773,7 +6777,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 1.0.5; + CURRENT_PROJECT_VERSION = 1.0.6; DEFINES_MODULE = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -6786,7 +6790,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 1.0.5; + MARKETING_VERSION = 1.0.6; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; diff --git a/Riot/AppDelegate.h b/Riot/AppDelegate.h index 79326d060..9d68fbc0e 100644 --- a/Riot/AppDelegate.h +++ b/Riot/AppDelegate.h @@ -74,7 +74,7 @@ extern NSString *const AppDelegateUniversalLinkDidChangeNotification; /** Let the AppDelegate handle and display self verification requests. - Default is YES; + Default is YES. */ @property (nonatomic) BOOL handleSelfVerificationRequest; diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index a8e1bfef7..bf9c2d2f4 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -237,6 +237,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni Related push notification service instance. Will be created when launch finished. */ @property (nonatomic, strong) PushNotificationService *pushNotificationService; +@property (nonatomic, strong) PushNotificationStore *pushNotificationStore; @property (nonatomic, strong) LocalAuthenticationService *localAuthenticationService; @property (nonatomic, strong) MajorUpdateManager *majorUpdateManager; @@ -412,23 +413,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni NSLog(@"[AppDelegate] didFinishLaunchingWithOptions"); #endif - // User credentials (in MXKAccount) are no more stored in NSUserDefaults but in a file - // as advised at https://forums.developer.apple.com/thread/15685#45849. - // So, there is no more need to loop (sometimes forever) until - // [application isProtectedDataAvailable] becomes YES. - // But, as we are not so sure, loop but no more than 10s. -// // TODO: Remove this loop. -// NSUInteger loopCount = 0; -// -// // Check whether the content protection is active before going further. -// // Should fix the spontaneous logout. -// while (![application isProtectedDataAvailable] && loopCount++ < 50) -// { -// // Wait for protected data. -// [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.2f]]; -// } -// -// NSLog(@"[AppDelegate] didFinishLaunchingWithOptions: isProtectedDataAvailable: %@ (%tu)", @([application isProtectedDataAvailable]), loopCount); NSLog(@"[AppDelegate] didFinishLaunchingWithOptions: isProtectedDataAvailable: %@", @([application isProtectedDataAvailable])); _configuration = [AppConfiguration new]; @@ -510,7 +494,8 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni self.localAuthenticationService = [[LocalAuthenticationService alloc] initWithPinCodePreferences:[PinCodePreferences shared]]; - self.pushNotificationService = [[PushNotificationService alloc] initWithPushNotificationManager:PushNotificationManager.shared]; + self.pushNotificationStore = [PushNotificationStore new]; + self.pushNotificationService = [[PushNotificationService alloc] initWithPushNotificationStore:self.pushNotificationStore]; self.pushNotificationService.delegate = self; // Add matrix observers, and initialize matrix sessions if the app is not launched in background. @@ -1993,14 +1978,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni // Use MXFileStore as MXStore to permanently store events. accountManager.storeClass = [MXFileStore class]; - - // Disable APNS use. -// if (accountManager.apnsDeviceToken) -// { -// // We use now Pushkit, unregister for all remote notifications received via Apple Push Notification service. -// [[UIApplication sharedApplication] unregisterForRemoteNotifications]; -// [accountManager setApnsDeviceToken:nil]; -// } // Observers have been defined, we can start a matrix session for each enabled accounts. NSLog(@"[AppDelegate] initMatrixSessions: prepareSessionForActiveAccounts (app state: %tu)", [[UIApplication sharedApplication] applicationState]); @@ -2250,8 +2227,8 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni // Reset user pin code [PinCodePreferences.shared reset]; - // Reset push notification manager - [PushNotificationManager.shared reset]; + // Reset push notification store + [self.pushNotificationStore reset]; #ifdef MX_CALL_STACK_ENDPOINT // Erase all created certificates and private keys by MXEndpointCallStack @@ -2430,6 +2407,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni // Stay in launching during the first server sync if the store is empty. isLaunching = (mainSession.rooms.count == 0 && launchAnimationContainerView); default: + isLaunching = NO; break; } diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 07aba72e5..463b8c003 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -1121,6 +1121,7 @@ "device_verification_self_verify_wait_recover_secrets_without_passphrase" = "Use Recovery Key"; "device_verification_self_verify_wait_recover_secrets_with_passphrase" = "Use Recovery Passphrase or Key"; "device_verification_self_verify_wait_recover_secrets_additional_information" = "If you can't accessing an existing session"; +"device_verification_self_verify_wait_recover_secrets_checking_availability" = "Checking for other verification capabilities ..."; // MARK: Verify diff --git a/Riot/Modules/Settings/Models/Row.m b/Riot/Categories/MXSessionState.swift similarity index 70% rename from Riot/Modules/Settings/Models/Row.m rename to Riot/Categories/MXSessionState.swift index a4dc62f0e..9f43992a8 100644 --- a/Riot/Modules/Settings/Models/Row.m +++ b/Riot/Categories/MXSessionState.swift @@ -14,22 +14,12 @@ // limitations under the License. // -#import "Row.h" +import Foundation -@implementation Row - -+ (instancetype)rowWithTag:(NSInteger)tag -{ - return [[self alloc] initWithTag:tag]; -} - -- (instancetype)initWithTag:(NSInteger)tag -{ - self = [super init]; - if (self) { - self.tag = tag; +extension MXSessionState: Comparable { + + public static func < (lhs: MXSessionState, rhs: MXSessionState) -> Bool { + return lhs.rawValue < rhs.rawValue } - return self; + } - -@end diff --git a/Riot/Generated/Images.swift b/Riot/Generated/Images.swift index 460817ddc..fd1c6d03e 100644 --- a/Riot/Generated/Images.swift +++ b/Riot/Generated/Images.swift @@ -135,7 +135,8 @@ internal struct ImageAsset { #if os(iOS) || os(tvOS) let image = Image(named: name, in: bundle, compatibleWith: nil) #elseif os(macOS) - let image = bundle.image(forResource: NSImage.Name(name)) + let name = NSImage.Name(self.name) + let image = (bundle == .main) ? NSImage(named: name) : bundle.image(forResource: name) #elseif os(watchOS) let image = Image(named: name) #endif diff --git a/Riot/Generated/InfoPlist.swift b/Riot/Generated/InfoPlist.swift index 95bdbe12c..98f156199 100644 --- a/Riot/Generated/InfoPlist.swift +++ b/Riot/Generated/InfoPlist.swift @@ -52,8 +52,7 @@ internal enum InfoPlist { // MARK: - Implementation Details private func arrayFromPlist(at path: String) -> [T] { - let bundle = BundleToken.bundle - guard let url = bundle.url(forResource: path, withExtension: nil), + guard let url = BundleToken.bundle.url(forResource: path, withExtension: nil), let data = NSArray(contentsOf: url) as? [T] else { fatalError("Unable to load PLIST at path: \(path)") } @@ -64,8 +63,7 @@ private struct PlistDocument { let data: [String: Any] init(path: String) { - let bundle = BundleToken.bundle - guard let url = bundle.url(forResource: path, withExtension: nil), + guard let url = BundleToken.bundle.url(forResource: path, withExtension: nil), let data = NSDictionary(contentsOf: url) as? [String: Any] else { fatalError("Unable to load PLIST at path: \(path)") } diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index ffdd4d08c..34a325d63 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -926,6 +926,10 @@ internal enum VectorL10n { internal static var deviceVerificationSelfVerifyWaitRecoverSecretsAdditionalInformation: String { return VectorL10n.tr("Vector", "device_verification_self_verify_wait_recover_secrets_additional_information") } + /// Checking for other verification capabilities ... + internal static var deviceVerificationSelfVerifyWaitRecoverSecretsCheckingAvailability: String { + return VectorL10n.tr("Vector", "device_verification_self_verify_wait_recover_secrets_checking_availability") + } /// Use Recovery Passphrase or Key internal static var deviceVerificationSelfVerifyWaitRecoverSecretsWithPassphrase: String { return VectorL10n.tr("Vector", "device_verification_self_verify_wait_recover_secrets_with_passphrase") diff --git a/Riot/Managers/PushNotification/PushNotificationService.h b/Riot/Managers/PushNotification/PushNotificationService.h index fc45a328a..24729adca 100644 --- a/Riot/Managers/PushNotification/PushNotificationService.h +++ b/Riot/Managers/PushNotification/PushNotificationService.h @@ -34,8 +34,8 @@ NS_ASSUME_NONNULL_BEGIN + (instancetype)new NS_UNAVAILABLE; /// Designated initializer -/// @param pushNotificationManager Push Notification Manager instance -- (instancetype)initWithPushNotificationManager:(PushNotificationManager *)pushNotificationManager; +/// @param pushNotificationStore Push Notification Store instance +- (instancetype)initWithPushNotificationStore:(PushNotificationStore *)pushNotificationStore; /** Is push really registered. diff --git a/Riot/Managers/PushNotification/PushNotificationService.m b/Riot/Managers/PushNotification/PushNotificationService.m index 87e1f4cc2..2b395a7e9 100644 --- a/Riot/Managers/PushNotification/PushNotificationService.m +++ b/Riot/Managers/PushNotification/PushNotificationService.m @@ -22,16 +22,14 @@ #import @interface PushNotificationService() -{ - /** - Matrix session observer used to detect new opened sessions. - */ - id matrixSessionStateObserver; -} +/** +Matrix session observer used to detect new opened sessions. +*/ +@property (nonatomic, weak) id matrixSessionStateObserver; @property (nonatomic, nullable, copy) void (^registrationForRemoteNotificationsCompletion)(NSError *); @property (nonatomic, strong) PKPushRegistry *pushRegistry; -@property (nonatomic, strong) PushNotificationManager *pushNotificationManager; +@property (nonatomic, strong) PushNotificationStore *pushNotificationStore; /// Should PushNotificationService receive VoIP pushes @property (nonatomic, assign) BOOL shouldReceiveVoIPPushes; @@ -40,11 +38,11 @@ @implementation PushNotificationService -- (instancetype)initWithPushNotificationManager:(PushNotificationManager *)pushNotificationManager +- (instancetype)initWithPushNotificationStore:(PushNotificationStore *)pushNotificationStore { if (self = [super init]) { - self.pushNotificationManager = pushNotificationManager; + self.pushNotificationStore = pushNotificationStore; _pushRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()]; self.shouldReceiveVoIPPushes = YES; } @@ -117,7 +115,7 @@ _isPushRegistered = YES; - if (!_pushNotificationManager.pushKitToken) + if (!_pushNotificationStore.pushKitToken) { [self configurePushKit]; } @@ -162,7 +160,7 @@ - (void)applicationDidEnterBackground { - if (_pushNotificationManager.pushKitToken) + if (_pushNotificationStore.pushKitToken) { self.shouldReceiveVoIPPushes = YES; } @@ -172,7 +170,7 @@ { [[UNUserNotificationCenter currentNotificationCenter] removeUnwantedNotifications]; [[UNUserNotificationCenter currentNotificationCenter] removeCallNotificationsFor:nil]; - if (_pushNotificationManager.pushKitToken) + if (_pushNotificationStore.pushKitToken) { self.shouldReceiveVoIPPushes = NO; } @@ -184,7 +182,7 @@ { _shouldReceiveVoIPPushes = shouldReceiveVoIPPushes; - if (_shouldReceiveVoIPPushes && _pushNotificationManager.pushKitToken) + if (_shouldReceiveVoIPPushes && _pushNotificationStore.pushKitToken) { MXSession *session = [AppDelegate theDelegate].mxSessions.firstObject; if (session.state >= MXSessionStateStoreDataReady) @@ -194,7 +192,11 @@ else { // add an observer for session state - matrixSessionStateObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXSessionStateDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { + MXWeakify(self); + + NSNotificationCenter * __weak notificationCenter = [NSNotificationCenter defaultCenter]; + self.matrixSessionStateObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXSessionStateDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { + MXStrongifyAndReturnIfNil(self); MXSession *mxSession = (MXSession*)notif.object; if ([[AppDelegate theDelegate].mxSessions containsObject:mxSession] @@ -202,8 +204,7 @@ && self->_shouldReceiveVoIPPushes) { [self configurePushKit]; - [[NSNotificationCenter defaultCenter] removeObserver:self->matrixSessionStateObserver]; - self->matrixSessionStateObserver = nil; + [notificationCenter removeObserver:self.matrixSessionStateObserver]; } }]; } @@ -230,15 +231,12 @@ if (account.mxSession.state == MXSessionStatePaused) { NSLog(@"[PushNotificationService] launchBackgroundSync"); - __weak typeof(self) weakSelf = self; + MXWeakify(self); [account backgroundSync:20000 success:^{ // Sanity check - if (!weakSelf) - { - return; - } + MXStrongifyAndReturnIfNil(self); [[UNUserNotificationCenter currentNotificationCenter] removeUnwantedNotifications]; [[UNUserNotificationCenter currentNotificationCenter] removeCallNotificationsFor:nil]; @@ -450,7 +448,7 @@ - (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)pushCredentials forType:(PKPushType)type { NSLog(@"[PushNotificationService] did update PushKit credentials"); - _pushNotificationManager.pushKitToken = pushCredentials.token; + _pushNotificationStore.pushKitToken = pushCredentials.token; if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) { self.shouldReceiveVoIPPushes = NO; @@ -459,7 +457,7 @@ - (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion { - NSLog(@"[PushNotificationService] did receive PushKit push with payload: %@", payload.dictionaryPayload); + NSLog(@"[PushNotificationService] didReceiveIncomingPushWithPayload: %@", payload.dictionaryPayload); NSString *roomId = payload.dictionaryPayload[@"room_id"]; NSString *eventId = payload.dictionaryPayload[@"event_id"]; @@ -469,14 +467,14 @@ if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) { - NSLog(@"[PushNotificationService] application is in bg"); + NSLog(@"[PushNotificationService] didReceiveIncomingPushWithPayload: application is in bg"); if (@available(iOS 13.0, *)) { // for iOS 13, we'll just report the incoming call in the same runloop. It means we cannot call an async API here. - MXEvent *lastCallInvite = _pushNotificationManager.lastCallInvite; + MXEvent *lastCallInvite = _pushNotificationStore.lastCallInvite; // remove event - _pushNotificationManager.lastCallInvite = nil; + _pushNotificationStore.lastCallInvite = nil; MXSession *session = [AppDelegate theDelegate].mxSessions.firstObject; // when we have a VoIP push while the application is killed, session.callManager will not be ready yet. Configure it. [[AppDelegate theDelegate] configureCallManagerIfRequiredForSession:session]; @@ -486,30 +484,26 @@ [session decryptEvent:lastCallInvite inTimeline:nil]; } - NSLog(@"[PushNotificationService] lastCallInvite: %@", lastCallInvite); + NSLog(@"[PushNotificationService] didReceiveIncomingPushWithPayload: lastCallInvite: %@", lastCallInvite); if ([lastCallInvite.eventId isEqualToString:eventId]) { - SEL handleCallInvite = NSSelectorFromString(@"handleCallInvite:"); - if ([session.callManager respondsToSelector:handleCallInvite]) - { - [session.callManager performSelector:handleCallInvite withObject:lastCallInvite]; - } + [session.callManager handleCallEvent:lastCallInvite]; MXCall *call = [session.callManager callWithCallId:lastCallInvite.content[@"call_id"]]; if (call) { [session.callManager.callKitAdapter reportIncomingCall:call]; - NSLog(@"[PushNotificationService] Reporting new call in room %@ for the event: %@", roomId, eventId); + NSLog(@"[PushNotificationService] didReceiveIncomingPushWithPayload: Reporting new call in room %@ for the event: %@", roomId, eventId); } else { - NSLog(@"[PushNotificationService] Error on call object on room %@ for the event: %@", roomId, eventId); + NSLog(@"[PushNotificationService] didReceiveIncomingPushWithPayload: Error on call object on room %@ for the event: %@", roomId, eventId); } } else { // It's a serious error. There is nothing to avoid iOS to kill us here. - NSLog(@"[PushNotificationService] iOS 13 and in bg, but we don't have the last callInvite event for the event %@. There is something wrong.", eventId); + NSLog(@"[PushNotificationService] didReceiveIncomingPushWithPayload: iOS 13 and in bg, but we don't have the last callInvite event for the event %@. There is something wrong.", eventId); } } else @@ -520,7 +514,7 @@ } else { - NSLog(@"[PushNotificationService] application is not in bg. There is something wrong."); + NSLog(@"[PushNotificationService] didReceiveIncomingPushWithPayload: application is not in bg. There is something wrong."); } completion(); diff --git a/Riot/Managers/PushNotification/PushNotificationManager.swift b/Riot/Managers/PushNotification/PushNotificationStore.swift similarity index 96% rename from Riot/Managers/PushNotification/PushNotificationManager.swift rename to Riot/Managers/PushNotification/PushNotificationStore.swift index fb5bd1633..694df3309 100644 --- a/Riot/Managers/PushNotification/PushNotificationManager.swift +++ b/Riot/Managers/PushNotification/PushNotificationStore.swift @@ -19,7 +19,7 @@ import KeychainAccess import MatrixSDK @objcMembers -final class PushNotificationManager: NSObject { +final class PushNotificationStore: NSObject { // MARK: - Constants @@ -32,8 +32,6 @@ final class PushNotificationManager: NSObject { static let lastCallInvite: String = "lastCallInvite" } - static let shared = PushNotificationManager() - /// Store. Defaults to `KeychainStore` private let store: KeyValueStore diff --git a/Riot/Modules/Authentication/AuthenticationViewController.m b/Riot/Modules/Authentication/AuthenticationViewController.m index f494903e5..907dfaac7 100644 --- a/Riot/Modules/Authentication/AuthenticationViewController.m +++ b/Riot/Modules/Authentication/AuthenticationViewController.m @@ -929,8 +929,15 @@ { authInputsview = (AuthInputsView*)self.authInputsView; } + + BOOL showForgotPasswordButton = NO; - self.forgotPasswordButton.hidden = (self.authType != MXKAuthenticationTypeLogin) || authInputsview.isSingleSignOnRequired; + if (BuildSettings.authScreenShowForgotPassword) + { + showForgotPasswordButton = (self.authType == MXKAuthenticationTypeLogin) && !authInputsview.isSingleSignOnRequired; + } + + self.forgotPasswordButton.hidden = !showForgotPasswordButton; // Adjust minimum leading constraint of the submit button if (self.forgotPasswordButton.isHidden) diff --git a/Riot/Modules/Authentication/Views/AuthInputsView.m b/Riot/Modules/Authentication/Views/AuthInputsView.m index 62fd27673..d944b017d 100644 --- a/Riot/Modules/Authentication/Views/AuthInputsView.m +++ b/Riot/Modules/Authentication/Views/AuthInputsView.m @@ -204,6 +204,8 @@ if ([self isFlowSupported:kMXLoginFlowTypePassword]) { + BOOL showPhoneTextField = BuildSettings.authScreenShowPhoneNumber; + self.passWordTextField.returnKeyType = UIReturnKeyDone; self.phoneTextField.returnKeyType = UIReturnKeyNext; @@ -219,13 +221,27 @@ attributes:@{NSForegroundColorAttributeName: ThemeService.shared.theme.placeholderTextColor}]; self.userLoginContainer.hidden = NO; - self.messageLabel.hidden = NO; - self.phoneContainer.hidden = NO; + self.messageLabel.hidden = !showPhoneTextField; + self.phoneContainer.hidden = !showPhoneTextField; self.passwordContainer.hidden = NO; self.messageLabelTopConstraint.constant = 59; - self.phoneContainerTopConstraint.constant = 70; - self.passwordContainerTopConstraint.constant = 150; + + CGFloat phoneContainerTopConstraintConstant = 0.0; + CGFloat passwordContainerTopConstraintConstant = 0.0; + + if (showPhoneTextField) + { + phoneContainerTopConstraintConstant = 70; + passwordContainerTopConstraintConstant = 150; + } + else + { + passwordContainerTopConstraintConstant = 50; + } + + self.phoneContainerTopConstraint.constant = phoneContainerTopConstraintConstant; + self.passwordContainerTopConstraint.constant = passwordContainerTopConstraintConstant; self.currentLastContainer = self.passwordContainer; } @@ -649,22 +665,9 @@ NSString *identityServer = restClient.identityServer; - // Create the next link that is common to all Vector.im clients - NSString *nextLink = [NSString stringWithFormat:@"%@/#/register?client_secret=%@&hs_url=%@&session_id=%@", - BuildSettings.applicationWebAppUrlString, - [self->submittedEmail.clientSecret stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]], - [restClient.homeserver stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]], - [self->currentSession.session stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]]]; - - if (identityServer) - { - nextLink = [NSString stringWithFormat:@"%@&is_url=%@", nextLink, - [identityServer stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]]]; - } - [self->submittedEmail requestValidationTokenWithMatrixRestClient:restClient isDuringRegistration:YES - nextLink:nextLink + nextLink:nil success:^ { NSMutableDictionary *threepidCreds = [NSMutableDictionary dictionaryWithDictionary:@{ diff --git a/Riot/Modules/Call/CallViewController.m b/Riot/Modules/Call/CallViewController.m index 0e4cc0951..011b4d46f 100644 --- a/Riot/Modules/Call/CallViewController.m +++ b/Riot/Modules/Call/CallViewController.m @@ -221,10 +221,6 @@ [super viewWillDisappear:animated]; } -- (void)dealloc -{ -} - #pragma mark - override MXKViewController - (void)destroy @@ -366,7 +362,7 @@ { // Detect if we should display the prompt to fallback to the STUN server defined // in the app plist if the homeserver does not provide STUN or TURN servers. - // We should if the call ends while we were in connecting state + // We should display it if the call ends while we were in connecting state if (!self.mainSession.callManager.turnServers && !self.mainSession.callManager.fallbackSTUNServer && !RiotSettings.shared.isAllowStunServerFallbackHasBeenSetOnce) @@ -388,6 +384,7 @@ } default: + // There is nothing to do for other states break; } } diff --git a/Riot/Modules/Camera/CameraAccessAlertPresenter.swift b/Riot/Modules/Camera/CameraAccessAlertPresenter.swift index 721e9f596..8005890c9 100644 --- a/Riot/Modules/Camera/CameraAccessAlertPresenter.swift +++ b/Riot/Modules/Camera/CameraAccessAlertPresenter.swift @@ -30,8 +30,7 @@ final class CameraAccessAlertPresenter { let alert = UIAlertController(title: VectorL10n.camera, message: VectorL10n.cameraAccessNotGranted(appDisplayName), preferredStyle: .alert) let cancelActionTitle = Bundle.mxk_localizedString(forKey: "ok") - let cancelAction = UIAlertAction(title: cancelActionTitle, style: .cancel, handler: { _ in - }) + let cancelAction = UIAlertAction(title: cancelActionTitle, style: .cancel) let settingsActionTitle = Bundle.mxk_localizedString(forKey: "settings") let settingsAction = UIAlertAction(title: settingsActionTitle, style: .default, handler: { _ in diff --git a/Riot/Modules/Settings/Models/Row.h b/Riot/Modules/Common/Models/Row.swift similarity index 68% rename from Riot/Modules/Settings/Models/Row.h rename to Riot/Modules/Common/Models/Row.swift index c39c314f1..eb9be24c0 100644 --- a/Riot/Modules/Settings/Models/Row.h +++ b/Riot/Modules/Common/Models/Row.swift @@ -14,19 +14,20 @@ // limitations under the License. // -#import +import Foundation -NS_ASSUME_NONNULL_BEGIN - -/// Row object for tableviews -@interface Row: NSObject - -@property (nonatomic, assign) NSInteger tag; - -+ (instancetype)rowWithTag:(NSInteger)tag; - -- (instancetype)initWithTag:(NSInteger)tag; - -@end - -NS_ASSUME_NONNULL_END +@objcMembers +final class Row: NSObject { + + let tag: Int + + init(withTag tag: Int) { + self.tag = tag + super.init() + } + + static func row(withTag tag: Int) -> Row { + return Row(withTag: tag) + } + +} diff --git a/Riot/Modules/Common/Models/Section.swift b/Riot/Modules/Common/Models/Section.swift new file mode 100644 index 000000000..024101da2 --- /dev/null +++ b/Riot/Modules/Common/Models/Section.swift @@ -0,0 +1,52 @@ +// +// Copyright 2020 Vector Creations 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 + +@objcMembers +final class Section: NSObject { + + let tag: Int + var rows: [Row] + var headerTitle: String? + + init(withTag tag: Int) { + self.tag = tag + self.rows = [] + super.init() + } + + static func section(withTag tag: Int) -> Section { + return Section(withTag: tag) + } + + func addRow(_ row: Row) { + rows.append(row) + } + + func addRow(withTag tag: Int) { + addRow(Row.row(withTag: tag)) + } + + func indexOfRow(withTag tag: Int) -> Int? { + return rows.firstIndex(where: { $0.tag == tag }) + } + + var hasAnyRows: Bool { + return rows.count > 0 + } + +} diff --git a/Riot/Modules/Common/Models/TableViewSections.swift b/Riot/Modules/Common/Models/TableViewSections.swift new file mode 100644 index 000000000..2f32c61e4 --- /dev/null +++ b/Riot/Modules/Common/Models/TableViewSections.swift @@ -0,0 +1,97 @@ +// +// Copyright 2020 Vector Creations 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 TableViewSectionsDelegate { + func tableViewSectionsDidUpdateSections(_ sections: TableViewSections) +} + +@objcMembers +final class TableViewSections: NSObject { + + /// Delegate object + weak var delegate: TableViewSectionsDelegate? + + /// Sections. Updating this will trigger `tableViewSectionsDidUpdateSections` of the delegate object. + var sections: [Section] = [] { + didSet { + delegate?.tableViewSectionsDidUpdateSections(self) + } + } + + /// Finds the exact indexpath for the given row and section tag. If cannot find, returns nil + /// - Parameters: + /// - rowTag: Tag for row + /// - sectionTag: Tag for section + /// - Returns: IndexPath object if found, otherwise nil. + func exactIndexPath(forRowTag rowTag: Int, sectionTag: Int) -> IndexPath? { + guard let sectionIndex = sections.firstIndex(where: { $0.tag == sectionTag }) else { + return nil + } + guard let indexOfRow = sections[sectionIndex].indexOfRow(withTag: rowTag) else { + return nil + } + return IndexPath(row: indexOfRow, section: sectionIndex) + } + + /// Finds the nearest next indexPath for given row tag and section tag. If the section finishes, also checks for the next section. If cannot find any row available, returns nil. + /// - Parameters: + /// - rowTag: Tag for row + /// - sectionTag: Tag for section + /// - Returns: IndexPath object if found, otherwise nil. + func nearestIndexPath(forRowTag rowTag: Int, sectionTag: Int) -> IndexPath? { + let sectionIndex = sections.firstIndex(where: { $0.tag == sectionTag }) + + if let sectionIndex = sectionIndex { + if let indexOfRow = sections[sectionIndex].indexOfRow(withTag: rowTag) { + return IndexPath(row: indexOfRow, section: sectionIndex) + } else if rowTag + 1 < sections[sectionIndex].rows.count { + return nearestIndexPath(forRowTag: rowTag + 1, sectionTag: sectionTag) + } else if sectionTag + 1 < sections.count { + return nearestIndexPath(forRowTag: 0, sectionTag: sectionTag + 1) + } + } else if sectionTag + 1 < sections.count { + // try to return the first row of the next section + return nearestIndexPath(forRowTag: 0, sectionTag: sectionTag + 1) + } + + return nil + } + + /// Section at index. + /// - Parameter index: Index of desired section + /// - Returns: Section object if index is in bounds of the sections array. Otherwise nil. + func section(atIndex index: Int) -> Section? { + if index < sections.count { + return sections[index] + } + return nil + } + + func tagsIndexPath(fromTableViewIndexPath indexPath: IndexPath) -> IndexPath? { + guard let section = section(atIndex: indexPath.section) else { + // section not found + return nil + } + guard indexPath.row < section.rows.count else { + return nil + } + return IndexPath(row: section.rows[indexPath.row].tag, section: section.tag) + } + +} diff --git a/Riot/Modules/Communities/GroupsViewController.m b/Riot/Modules/Communities/GroupsViewController.m index 7596397d1..94b4a47cd 100644 --- a/Riot/Modules/Communities/GroupsViewController.m +++ b/Riot/Modules/Communities/GroupsViewController.m @@ -615,48 +615,6 @@ currentAlert = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet]; -// [currentAlert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"room_recents_start_chat_with", @"Vector", nil) -// style:UIAlertActionStyleDefault -// handler:^(UIAlertAction * action) { -// -// if (weakSelf) -// { -// typeof(self) self = weakSelf; -// self->currentAlert = nil; -// -// [self performSegueWithIdentifier:@"presentStartChat" sender:self]; -// } -// -// }]]; -// -// [currentAlert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"room_recents_create_empty_room", @"Vector", nil) -// style:UIAlertActionStyleDefault -// handler:^(UIAlertAction * action) { -// -// if (weakSelf) -// { -// typeof(self) self = weakSelf; -// self->currentAlert = nil; -// -// [self createAnEmptyRoom]; -// } -// -// }]]; -// -// [currentAlert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"room_recents_join_room", @"Vector", nil) -// style:UIAlertActionStyleDefault -// handler:^(UIAlertAction * action) { -// -// if (weakSelf) -// { -// typeof(self) self = weakSelf; -// self->currentAlert = nil; -// -// [self joinARoom]; -// } -// -// }]]; - [currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"] style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { @@ -676,76 +634,6 @@ [self presentViewController:currentAlert animated:YES completion:nil]; } -//- (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:UIAlertActionStyleDefault -// 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->currentRequest = [self.mainSession joinRoom:roomAliasOrId 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]; -// }]; -// } -// -// }]]; -// -// [currentAlert mxk_setAccessibilityIdentifier:@"RecentsVCJoinARoomAlert"]; -// [self presentViewController:currentAlert animated:YES completion:nil]; -//} - #pragma mark - Table view scrolling - (void)scrollToTop:(BOOL)animated diff --git a/Riot/Modules/Communities/Rooms/GroupRoomsViewController.m b/Riot/Modules/Communities/Rooms/GroupRoomsViewController.m index 4b017b6c7..4709fb3ed 100644 --- a/Riot/Modules/Communities/Rooms/GroupRoomsViewController.m +++ b/Riot/Modules/Communities/Rooms/GroupRoomsViewController.m @@ -577,25 +577,6 @@ [tableView deselectRowAtIndexPath:indexPath animated:YES]; } -//- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath -//{ -// NSMutableArray* actions; -// -// // @TODO Add the swipe to remove this room from the community if the current user is admin -// actions = [[NSMutableArray alloc] init]; -// -// // Patch: Force the width of the button by adding whitespace characters into the title string. -// UITableViewRowAction *leaveAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive title:@" " handler:^(UITableViewRowAction *action, NSIndexPath *indexPath){ -// -// // @TODO Remove the room -// -// }]; -// -// leaveAction.backgroundColor = [MXKTools convertImageToPatternColor:@"remove_icon_blue" backgroundColor:ThemeService.shared.theme.headerBackgroundColor patternSize:CGSizeMake(74, 74) resourceSize:CGSizeMake(24, 24)]; -// [actions insertObject:leaveAction atIndex:0]; -// -// return actions; -//} #pragma mark - UISearchBar delegate diff --git a/Riot/Modules/Favorites/FavouritesViewController.m b/Riot/Modules/Favorites/FavouritesViewController.m index 2d25a983f..24b499f6b 100644 --- a/Riot/Modules/Favorites/FavouritesViewController.m +++ b/Riot/Modules/Favorites/FavouritesViewController.m @@ -66,11 +66,6 @@ } } -- (void)dealloc -{ - -} - - (void)destroy { [super destroy]; diff --git a/Riot/Modules/Home/HomeViewController.m b/Riot/Modules/Home/HomeViewController.m index b304cb53e..8191800c4 100644 --- a/Riot/Modules/Home/HomeViewController.m +++ b/Riot/Modules/Home/HomeViewController.m @@ -114,11 +114,6 @@ [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; } -- (void)dealloc -{ - -} - - (void)destroy { [super destroy]; diff --git a/Riot/Modules/Integrations/IntegrationManagerViewController.m b/Riot/Modules/Integrations/IntegrationManagerViewController.m index ea29bdb7d..9f1af8d9c 100644 --- a/Riot/Modules/Integrations/IntegrationManagerViewController.m +++ b/Riot/Modules/Integrations/IntegrationManagerViewController.m @@ -349,7 +349,7 @@ NSString *const kIntegrationManagerAddIntegrationScreen = @"add_integ"; if (!widget_id) { - [self sendLocalisedError:@"widget_integration_unable_to_create" toRequest:requestId]; // new Error("Missing required widget fields.")); + [self sendLocalisedError:@"widget_integration_unable_to_create" toRequest:requestId]; return; } diff --git a/Riot/Modules/Integrations/Widgets/Jitsi/JitsiViewController.m b/Riot/Modules/Integrations/Widgets/Jitsi/JitsiViewController.m index 680db5638..3d5cee140 100644 --- a/Riot/Modules/Integrations/Widgets/Jitsi/JitsiViewController.m +++ b/Riot/Modules/Integrations/Widgets/Jitsi/JitsiViewController.m @@ -213,10 +213,12 @@ static const NSString *kJitsiDataErrorKey = @"error"; - (void)conferenceWillJoin:(NSDictionary *)data { + // Nothing to do } - (void)conferenceJoined:(NSDictionary *)data { + // Nothing to do } - (void)conferenceTerminated:(NSDictionary *)data diff --git a/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewModel.swift b/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewModel.swift index 408a404df..cef1d7c0c 100644 --- a/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewModel.swift +++ b/Riot/Modules/KeyBackup/Recover/PrivateKey/KeyBackupRecoverFromPrivateKeyViewModel.swift @@ -40,8 +40,6 @@ final class KeyBackupRecoverFromPrivateKeyViewModel: KeyBackupRecoverFromPrivate self.keyBackupVersion = keyBackupVersion } - deinit { - } // MARK: - Public diff --git a/Riot/Modules/KeyVerification/Common/KeyVerificationCoordinatorBridgePresenter.swift b/Riot/Modules/KeyVerification/Common/KeyVerificationCoordinatorBridgePresenter.swift index 3b9e9fac3..52e7e932e 100644 --- a/Riot/Modules/KeyVerification/Common/KeyVerificationCoordinatorBridgePresenter.swift +++ b/Riot/Modules/KeyVerification/Common/KeyVerificationCoordinatorBridgePresenter.swift @@ -128,7 +128,9 @@ final class KeyVerificationCoordinatorBridgePresenter: NSObject { private func present(coordinator keyVerificationCoordinator: KeyVerificationCoordinator, from viewController: UIViewController, animated: Bool) { keyVerificationCoordinator.delegate = self - viewController.present(keyVerificationCoordinator.toPresentable(), animated: animated, completion: nil) + let presentable = keyVerificationCoordinator.toPresentable() + presentable.presentationController?.delegate = self + viewController.present(presentable, animated: animated, completion: nil) keyVerificationCoordinator.start() self.coordinator = keyVerificationCoordinator @@ -146,3 +148,13 @@ extension KeyVerificationCoordinatorBridgePresenter: KeyVerificationCoordinatorD self.delegate?.keyVerificationCoordinatorBridgePresenterDelegateDidCancel(self) } } + +extension KeyVerificationCoordinatorBridgePresenter: UIAdaptivePresentationControllerDelegate { + + func presentationControllerDidDismiss(_ presentationController: UIPresentationController) { + if let coordinator = self.coordinator { + keyVerificationCoordinatorDidCancel(coordinator) + } + } + +} diff --git a/Riot/Modules/KeyVerification/Common/ScanConfirmation/KeyVerificationScanConfirmationViewModel.swift b/Riot/Modules/KeyVerification/Common/ScanConfirmation/KeyVerificationScanConfirmationViewModel.swift index 7407a0e2f..b0ad17441 100644 --- a/Riot/Modules/KeyVerification/Common/ScanConfirmation/KeyVerificationScanConfirmationViewModel.swift +++ b/Riot/Modules/KeyVerification/Common/ScanConfirmation/KeyVerificationScanConfirmationViewModel.swift @@ -53,9 +53,6 @@ final class KeyVerificationScanConfirmationViewModel: KeyVerificationScanConfirm self.verificationKind = verificationKind } - deinit { - } - // MARK: - Public func process(viewAction: KeyVerificationScanConfirmationViewAction) { diff --git a/Riot/Modules/KeyVerification/Common/Verify/SAS/KeyVerificationVerifyBySASViewModel.swift b/Riot/Modules/KeyVerification/Common/Verify/SAS/KeyVerificationVerifyBySASViewModel.swift index 3f066437e..7ab3c504e 100644 --- a/Riot/Modules/KeyVerification/Common/Verify/SAS/KeyVerificationVerifyBySASViewModel.swift +++ b/Riot/Modules/KeyVerification/Common/Verify/SAS/KeyVerificationVerifyBySASViewModel.swift @@ -46,9 +46,6 @@ final class KeyVerificationVerifyBySASViewModel: KeyVerificationVerifyBySASViewM self.verificationKind = verificationKind } - deinit { - } - // MARK: - Public func process(viewAction: KeyVerificationVerifyBySASViewAction) { diff --git a/Riot/Modules/KeyVerification/Device/Incoming/DeviceVerificationIncomingViewModel.swift b/Riot/Modules/KeyVerification/Device/Incoming/DeviceVerificationIncomingViewModel.swift index 3652fd29b..69a324221 100644 --- a/Riot/Modules/KeyVerification/Device/Incoming/DeviceVerificationIncomingViewModel.swift +++ b/Riot/Modules/KeyVerification/Device/Incoming/DeviceVerificationIncomingViewModel.swift @@ -51,10 +51,7 @@ final class DeviceVerificationIncomingViewModel: DeviceVerificationIncomingViewM self.mediaManager = session.mediaManager } - - deinit { - } - + // MARK: - Public func process(viewAction: DeviceVerificationIncomingViewAction) { diff --git a/Riot/Modules/KeyVerification/Device/SelfVerifyStart/KeyVerificationSelfVerifyStartViewModel.swift b/Riot/Modules/KeyVerification/Device/SelfVerifyStart/KeyVerificationSelfVerifyStartViewModel.swift index b4f3e63ac..07202d705 100644 --- a/Riot/Modules/KeyVerification/Device/SelfVerifyStart/KeyVerificationSelfVerifyStartViewModel.swift +++ b/Riot/Modules/KeyVerification/Device/SelfVerifyStart/KeyVerificationSelfVerifyStartViewModel.swift @@ -45,9 +45,6 @@ final class KeyVerificationSelfVerifyStartViewModel: KeyVerificationSelfVerifySt self.keyVerificationService = KeyVerificationService() } - deinit { - } - // MARK: - Public func process(viewAction: KeyVerificationSelfVerifyStartViewAction) { diff --git a/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewController.storyboard b/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewController.storyboard index a854f8878..d3db75f1f 100644 --- a/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewController.storyboard +++ b/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewController.storyboard @@ -1,11 +1,9 @@ - - - - + + - + @@ -19,16 +17,16 @@ - + - + - + - + @@ -85,19 +83,43 @@ Riot X for Android - + + + + + + + + + + + + + + + + + + + + - +