Merged element 1.11.3 into bum

This commit is contained in:
Arnfried Griesert
2023-09-29 05:24:53 +02:00
36 changed files with 452 additions and 180 deletions

View File

@@ -38,5 +38,6 @@ targets:
sources:
- path: .
- path: ../Config/BuildSettings.swift
- path: ../Config/MDMSettings.swift
- path: ../Riot/Categories/Bundle.swift
- path: ../Riot/Modules/Room/TimelineCells/Styles/RoomTimelineStyleIdentifier.swift

View File

@@ -1,3 +1,23 @@
## Changes in 1.11.3 (2023-09-13)
🐛 Bugfixes
- Show OIDC account management UI using embedded browser instead of system browser. ([#7671](https://github.com/vector-im/element-ios/issues/7671))
- Hide Sign Out X/All Sessions buttons in the Device Manager when using OIDC. ([#7672](https://github.com/vector-im/element-ios/issues/7672))
## Changes in 1.11.2 (2023-09-12)
🙌 Improvements
- Upgrade MatrixSDK version ([v0.27.2](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.27.2)).
🐛 Bugfixes
- Fix an issue where rooms were not correctly sorted after forwarding a message. ([#7641](https://github.com/vector-im/element-ios/issues/7641))
- Add phone number UI and explanatory text is hidden if the 3 pid changes capability is disabled. ([#7670](https://github.com/vector-im/element-ios/issues/7670))
## Changes in 1.11.1 (2023-08-29)
✨ Features

View File

@@ -102,13 +102,16 @@ final class BuildSettings: NSObject {
static let forceHomeserverSelection = false
/// Default server proposed on the authentication screen
static let serverConfigDefaultHomeserverUrlString = "https://matrix.org"
static var serverConfigDefaultHomeserverUrlString: String {
MDMSettings.serverConfigDefaultHomeserverUrlString ?? "https://matrix.org"
}
/// Default identity server
static let serverConfigDefaultIdentityServerUrlString = "https://vector.im"
static let serverConfigSygnalAPIUrlString = "https://matrix.org/_matrix/push/v1/notify"
static var serverConfigSygnalAPIUrlString: String {
MDMSettings.serverConfigSygnalAPIUrlString ?? "https://matrix.org/_matrix/push/v1/notify"
}
// MARK: - Legal URLs
@@ -144,7 +147,9 @@ final class BuildSettings: NSObject {
// This baseURL is used to generate permalinks within the app (E.g. timeline message permalinks).
// Optional String that when set is used as permalink base, when nil matrix.to format is used.
// Example value would be "https://www.example.com", note there is no trailing '/'.
static let clientPermalinkBaseUrl: String? = nil
static var clientPermalinkBaseUrl: String? {
MDMSettings.clientPermalinkBaseUrl
}
// MARK: - VoIP
static var allowVoIPUsage: Bool {

52
Config/MDMSettings.swift Normal file
View File

@@ -0,0 +1,52 @@
//
// Copyright 2023 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
enum MDMSettings {
private static let appleManagedConfigurationKey = "com.apple.configuration.managed"
private enum Key: String {
case serverConfigDefaultHomeserverUrlString = "im.vector.app.serverConfigDefaultHomeserverUrlString"
case serverConfigSygnalAPIUrlString = "im.vector.app.serverConfigSygnalAPIUrlString"
case clientPermalinkBaseUrl = "im.vector.app.clientPermalinkBaseUrl"
}
static var serverConfigDefaultHomeserverUrlString: String? {
valueForKey(.serverConfigDefaultHomeserverUrlString) as? String
}
static var serverConfigSygnalAPIUrlString: String? {
valueForKey(.serverConfigSygnalAPIUrlString) as? String
}
static var clientPermalinkBaseUrl: String? {
valueForKey(.clientPermalinkBaseUrl) as? String
}
// MARK: - Private
static private func valueForKey(_ key: Key) -> Any? {
guard let managedConfiguration = UserDefaults.standard.dictionary(forKey: appleManagedConfigurationKey) else {
print("MDM configuration missing")
return nil
}
print("Retrieved MDM configuration: \(managedConfiguration)")
return managedConfiguration[key.rawValue]
}
}

View File

@@ -71,6 +71,25 @@ Be sure to use compatible branches for Element iOS and MatrixSDK. For example, i
**Important**: By working with [XcodeGen](https://github.com/yonaskolb/XcodeGen) you will need to use the _New Build System_ in Xcode, to have your some of the xcconfig variables taken into account. It should be enabled by default on the latest Xcode versions, but if you need to enable it go to Xcode menu and select `File > Workspace Settings… > Build System` and then choose `New Build System`.
- **Running a local rust MatrixCryptoSDK locally**
If you want to debug locally or test local changes of the rust `MatrixSDKCrypto` with a local `MatrixSDK`, you must checkout [matrix-rust-sdk](https://github.com/matrix-org/matrix-rust-sdk), and follow the [instructions in the repository](https://github.com/matrix-org/matrix-rust-sdk/tree/main/bindings/apple).
Once the framework is built using `./build_crypto_xcframework.sh` you will have to move `bindings/apple/MatrixSDKCrypto-Local.podspec` to the root of the `matrix-rust-sdk` folder and rename it to `MatrixSDKCrypto.podspec` then update `s.version` with the current pod version:
```
s.version = "0.3.12"
```
Then in the element-ios `Podfile`, add the following line under the existing `pod 'MatrixSDK' [..]`:
```
pod 'MatrixSDKCrypto', :path => '../matrix-rust-sdk/MatrixSDKCrypto.podspec'
```
Run `pod install` to refresh all.
### `$matrixSDKVersion` Modification
Every time you change the `$matrixSDKVersion` variable in the `Podfile`, you have to run the `pod install` command again.

View File

@@ -16,7 +16,7 @@ use_frameworks!
# - `{ :specHash => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for MatrixSDK 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
$matrixSDKVersion = '= 0.27.1'
$matrixSDKVersion = '= 0.27.2'
# $matrixSDKVersion = :local
# $matrixSDKVersion = { :branch => 'develop'}
# $matrixSDKVersion = { :specHash => { git: 'https://git.io/fork123', branch: 'fix' } }

View File

@@ -20,31 +20,13 @@ PODS:
- Down (0.11.0)
- DSBottomSheet (0.3.0)
- DSWaveformImage (6.1.1)
- DTCoreText (1.6.26):
- DTCoreText/Core (= 1.6.26)
- DTFoundation/Core (~> 1.7.5)
- DTFoundation/DTAnimatedGIF (~> 1.7.5)
- DTFoundation/DTHTMLParser (~> 1.7.5)
- DTFoundation/UIKit (~> 1.7.5)
- DTCoreText/Core (1.6.26):
- DTFoundation/Core (~> 1.7.5)
- DTFoundation/DTAnimatedGIF (~> 1.7.5)
- DTFoundation/DTHTMLParser (~> 1.7.5)
- DTFoundation/UIKit (~> 1.7.5)
- DTFoundation/Core (1.7.18)
- DTFoundation/DTAnimatedGIF (1.7.18)
- DTFoundation/DTHTMLParser (1.7.18):
- DTFoundation/Core
- DTFoundation/UIKit (1.7.18):
- DTFoundation/Core
- DTTJailbreakDetection (0.4.0)
- FLEX (4.5.0)
- FlowCommoniOS (1.12.2)
- GBDeviceInfo (7.1.0):
- GBDeviceInfo/Core (= 7.1.0)
- GBDeviceInfo/Core (7.1.0)
- GZIP (1.3.0)
- Introspect (0.12.0)
- Introspect (0.11.0)
- JitsiMeetSDKLite (8.1.2-lite):
- JitsiWebRTC (~> 111.0)
- JitsiWebRTC (111.0.2)
@@ -57,12 +39,9 @@ PODS:
- LoggerAPI (1.9.200):
- Logging (~> 1.1)
- Logging (1.4.0)
- MatomoTracker (7.5.2):
- MatomoTracker/Core (= 7.5.2)
- MatomoTracker/Core (7.5.2)
- MatrixSDK (0.27.1):
- MatrixSDK/Core (= 0.27.1)
- MatrixSDK/Core (0.27.1):
- MatrixSDK (0.27.2):
- MatrixSDK/Core (= 0.27.2)
- MatrixSDK/Core (0.27.2):
- AFNetworking (~> 4.0.0)
- GZIP (~> 1.3.0)
- libbase58 (~> 0.1.4)
@@ -70,7 +49,7 @@ PODS:
- OLMKit (~> 3.2.5)
- Realm (= 10.27.0)
- SwiftyBeaver (= 1.9.5)
- MatrixSDK/JingleCallStack (0.27.1):
- MatrixSDK/JingleCallStack (0.27.2):
- JitsiMeetSDKLite (= 8.1.2-lite)
- MatrixSDK/Core
- MatrixSDKCrypto (0.3.12)
@@ -79,7 +58,7 @@ PODS:
- OLMKit/olmcpp (= 3.2.12)
- OLMKit/olmc (3.2.12)
- OLMKit/olmcpp (3.2.12)
- PostHog (2.0.2)
- PostHog (2.0.0)
- ReadMoreTextView (3.0.1)
- Realm (10.27.0):
- Realm/Headers (= 10.27.0)
@@ -94,7 +73,7 @@ PODS:
- Sentry/Core (7.15.0)
- SideMenu (6.5.0)
- SwiftBase32 (0.9.0)
- SwiftFormat/CLI (0.52.3)
- SwiftFormat/CLI (0.50.2)
- SwiftGen (6.6.2)
- SwiftJWT (3.6.200):
- BlueCryptor (~> 1.0)
@@ -102,7 +81,7 @@ PODS:
- BlueRSA (~> 1.0)
- KituraContracts (~> 1.2)
- LoggerAPI (~> 1.7)
- SwiftLint (0.52.4)
- SwiftLint (0.49.1)
- SwiftyBeaver (1.9.5)
- UICollectionViewLeftAlignedLayout (1.0.2)
- UICollectionViewRightAlignedLayout (0.0.3)
@@ -116,8 +95,6 @@ DEPENDENCIES:
- Down (~> 0.11.0)
- DSBottomSheet (~> 0.3)
- DSWaveformImage (~> 6.1.1)
- DTCoreText (= 1.6.26)
- DTTJailbreakDetection (~> 0.4.0)
- FLEX (~> 4.5.0)
- FlowCommoniOS (~> 1.12.0)
- GBDeviceInfo (~> 7.1.0)
@@ -125,9 +102,8 @@ DEPENDENCIES:
- KeychainAccess (~> 4.2.2)
- KTCenterFlowLayout (~> 1.3.1)
- libPhoneNumber-iOS (~> 0.9.13)
- MatomoTracker (~> 7.5.2)
- MatrixSDK (from `https://dl-gitlab.example.com/bwmessenger/bundesmessenger/bundesmessenger-ios-sdk`, tag `v2.10.0_rc2`)
- MatrixSDK/JingleCallStack (from `https://dl-gitlab.example.com/bwmessenger/bundesmessenger/bundesmessenger-ios-sdk`, tag `v2.10.0_rc2`)
- MatrixSDK (= 0.27.2)
- MatrixSDK/JingleCallStack (= 0.27.2)
- OLMKit
- PostHog (~> 2.0.0)
- ReadMoreTextView (~> 3.0.1)
@@ -146,7 +122,7 @@ DEPENDENCIES:
- ZXingObjC (~> 3.6.5)
SPEC REPOS:
https://github.com/CocoaPods/Specs.git:
trunk:
- AFNetworking
- BlueCryptor
- BlueECC
@@ -154,9 +130,6 @@ SPEC REPOS:
- Down
- DSBottomSheet
- DSWaveformImage
- DTCoreText
- DTFoundation
- DTTJailbreakDetection
- FLEX
- FlowCommoniOS
- GBDeviceInfo
@@ -171,7 +144,7 @@ SPEC REPOS:
- libPhoneNumber-iOS
- LoggerAPI
- Logging
- MatomoTracker
- MatrixSDK
- MatrixSDKCrypto
- OLMKit
- PostHog
@@ -192,16 +165,6 @@ SPEC REPOS:
- zxcvbn-ios
- ZXingObjC
EXTERNAL SOURCES:
MatrixSDK:
:git: https://dl-gitlab.example.com/bwmessenger/bundesmessenger/bundesmessenger-ios-sdk
:tag: v2.10.0_rc2
CHECKOUT OPTIONS:
MatrixSDK:
:git: https://dl-gitlab.example.com/bwmessenger/bundesmessenger/bundesmessenger-ios-sdk
:tag: v2.10.0_rc2
SPEC CHECKSUMS:
AFNetworking: 3bd23d814e976cd148d7d44c3ab78017b744cd58
BlueCryptor: b0aee3d9b8f367b49b30de11cda90e1735571c24
@@ -210,14 +173,11 @@ SPEC CHECKSUMS:
Down: b6ba1bc985c9d2f4e15e3b293d2207766fa12612
DSBottomSheet: ca0ac37eb5af2dd54663f86b84382ed90a59be2a
DSWaveformImage: 3c718a0cf99291887ee70d1d0c18d80101d3d9ce
DTCoreText: ec749e013f2e1f76de5e7c7634642e600a7467ce
DTFoundation: a53f8cda2489208cbc71c648be177f902ee17536
DTTJailbreakDetection: 5e356c5badc17995f65a83ed9483f787a0057b71
FLEX: e51461dd6f0bfb00643c262acdfea5d5d12c596b
FlowCommoniOS: ca92071ab526dc89905495a37844fd7e78d1a7f2
GBDeviceInfo: 5d62fa85bdcce3ed288d83c28789adf1173e4376
GZIP: 416858efbe66b41b206895ac6dfd5493200d95b3
Introspect: b66b675de8a85d9ef832f3a710d8e3c7db186884
Introspect: 4cc1e4c34dd016540c8d86a591c231c09dafbee3
JitsiMeetSDKLite: 895213158cf62342069a10634a41d2f1c00057f7
JitsiWebRTC: 80f62908fcf2a1160e0d14b584323fb6e6be630b
KeychainAccess: c0c4f7f38f6fc7bbe58f5702e25f7bd2f65abf51
@@ -227,21 +187,20 @@ SPEC CHECKSUMS:
libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75
LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d
Logging: beeb016c9c80cf77042d62e83495816847ef108b
MatomoTracker: 1d98ddc58322fd9d65e1a6886b8e41363047bd13
MatrixSDK: f6c197ca06aab29ff69d1105965a57d277dfcd9d
MatrixSDK: a39e229a03a00394e055ffa7490e9602d45f8a44
MatrixSDKCrypto: 25929a40733b4ab54f659aaf6a730552a0a06504
OLMKit: da115f16582e47626616874e20f7bb92222c7a51
PostHog: f9e5c13ceea86bb5314218c85d16125b797eb332
PostHog: 660ec6c9d80cec17b685e148f17f6785a88b597d
ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d
Realm: 9ca328bd7e700cc19703799785e37f77d1a130f2
Reusable: 6bae6a5e8aa793c9c441db0213c863a64bce9136
Sentry: 63ca44f5e0c8cea0ee5a07686b02e56104f41ef7
SideMenu: f583187d21c5b1dd04c72002be544b555a2627a2
SwiftBase32: 9399c25a80666dc66b51e10076bf591e3bbb8f17
SwiftFormat: 5de81c42f043741a16e17ae2da012bbddc7c0b58
SwiftFormat: 710117321c55c82675c0dc03055128efbb13c38f
SwiftGen: 1366a7f71aeef49954ca5a63ba4bef6b0f24138c
SwiftJWT: 88c412708f58c169d431d344c87bc79a87c830ae
SwiftLint: 1cc5cd61ba9bacb2194e340aeb47a2a37fda00b3
SwiftLint: 32ee33ded0636d0905ef6911b2b67bbaeeedafa5
SwiftyBeaver: 84069991dd5dca07d7069100985badaca7f0ce82
UICollectionViewLeftAlignedLayout: 830bf6fa5bab9f9b464f62e3384f9d2e00b3c0f6
UICollectionViewRightAlignedLayout: 823eef8c567eba4a44c21bc2ffcb0d0d5f361e2d
@@ -249,6 +208,6 @@ SPEC CHECKSUMS:
zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
PODFILE CHECKSUM: e7f4847564a30ed02659a311fe204021498f30e8
PODFILE CHECKSUM: b926e281576aabcdbc2bdcb40ef3ad3e0991abe8
COCOAPODS: 1.11.3

View File

@@ -0,0 +1,48 @@
//
// Copyright 2020 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
@objcMembers
/// A service for the SSOAuthenticationPresenter that allows to open an OIDC account management URL.
///
/// Both `callBackURLScheme` and `loginToken` are unneeded for this use case and return `nil`.
final class SSOAccountService: NSObject, SSOAuthenticationServiceProtocol {
// MARK: - Properties
private let accountURL: URL
let callBackURLScheme: String? = nil
// MARK: - Setup
init(accountURL: URL) {
self.accountURL = accountURL
super.init()
}
// MARK: - Public
func authenticationURL(for identityProvider: String?, transactionId: String) -> URL? {
accountURL
}
func loginToken(from url: URL) -> String? {
MXLog.error("The account service shouldn't receive a completion callback.")
return nil
}
}

View File

@@ -37,7 +37,7 @@ final class SSOAuthenticationPresenter: NSObject {
// MARK: - Properties
private let ssoAuthenticationService: SSOAuthenticationService
private let ssoAuthenticationService: SSOAuthenticationServiceProtocol
// MARK: Private
@@ -53,7 +53,7 @@ final class SSOAuthenticationPresenter: NSObject {
// MARK: - Setup
init(ssoAuthenticationService: SSOAuthenticationService) {
init(ssoAuthenticationService: SSOAuthenticationServiceProtocol) {
self.ssoAuthenticationService = ssoAuthenticationService
super.init()
}

View File

@@ -22,8 +22,16 @@ enum SSOAuthenticationServiceError: Error {
case unknown
}
@objc protocol SSOAuthenticationServiceProtocol {
var callBackURLScheme: String? { get }
func authenticationURL(for identityProvider: String?, transactionId: String) -> URL?
func loginToken(from url: URL) -> String?
}
@objcMembers
final class SSOAuthenticationService: NSObject {
final class SSOAuthenticationService: NSObject, SSOAuthenticationServiceProtocol {
// MARK: - Constants

View File

@@ -4634,7 +4634,8 @@ static CGSize kThreadListBarButtonItemImageSize;
{
ForwardingShareItemSender *shareItemSender = [[ForwardingShareItemSender alloc] initWithEvent:selectedEvent];
self.shareManager = [[ShareManager alloc] initWithShareItemSender:shareItemSender
type:ShareManagerTypeForward];
type:ShareManagerTypeForward
session:self.mainSession];
MXWeakify(self);
[self.shareManager setCompletionCallback:^(ShareManagerResult result) {

View File

@@ -46,7 +46,7 @@ enum {
};
@interface ManageSessionViewController () <UserVerificationCoordinatorBridgePresenterDelegate>
@interface ManageSessionViewController () <UserVerificationCoordinatorBridgePresenterDelegate, SSOAuthenticationPresenterDelegate>
{
// The device to display
MXDevice *device;
@@ -65,6 +65,8 @@ enum {
@property (nonatomic, strong) ReauthenticationCoordinatorBridgePresenter *reauthenticationCoordinatorBridgePresenter;
@property (nonatomic, strong) SSOAuthenticationPresenter *ssoAuthenticationPresenter;
@end
@implementation ManageSessionViewController
@@ -701,17 +703,19 @@ enum {
{
UIAlertController *alert = [UIAlertController alertControllerWithTitle: [VectorL10n manageSessionRedirect] message: nil preferredStyle:UIAlertControllerStyleAlert];
__weak typeof(self) weakSelf = self;
MXWeakify(self);
UIAlertAction *action = [UIAlertAction actionWithTitle:[VectorL10n ok]
style:UIAlertActionStyleDefault
handler: ^(UIAlertAction * action) {
[UIApplication.sharedApplication openURL:url options:@{} completionHandler:^(BOOL success) {
if (success && weakSelf)
{
[weakSelf withdrawViewControllerAnimated:YES completion:nil];
}
}];
MXStrongifyAndReturnIfNil(self);
SSOAccountService *service = [[SSOAccountService alloc] initWithAccountURL:url];
SSOAuthenticationPresenter *presenter = [[SSOAuthenticationPresenter alloc] initWithSsoAuthenticationService:service];
presenter.delegate = self;
self.ssoAuthenticationPresenter = presenter;
[presenter presentForIdentityProvider:nil with:@"" from:self animated:YES];
}];
[alert addAction: action];
[self presentViewController:alert animated:YES completion:nil];
}
@@ -777,4 +781,27 @@ enum {
[self reloadDeviceWithCompletion:^{}];
}
#pragma mark - SSOAuthenticationPresenterDelegate
- (void)ssoAuthenticationPresenterDidCancel:(SSOAuthenticationPresenter *)presenter
{
self.ssoAuthenticationPresenter = nil;
MXLogDebug(@"OIDC account management complete.")
[self withdrawViewControllerAnimated:YES completion:nil];
}
- (void)ssoAuthenticationPresenter:(SSOAuthenticationPresenter *)presenter authenticationDidFailWithError:(NSError *)error
{
self.ssoAuthenticationPresenter = nil;
MXLogError(@"OIDC account management failed.")
}
- (void)ssoAuthenticationPresenter:(SSOAuthenticationPresenter *)presenter
authenticationSucceededWithToken:(NSString *)token
usingIdentityProvider:(SSOIdentityProvider *)identityProvider
{
self.ssoAuthenticationPresenter = nil;
MXLogWarning(@"Unexpected callback after OIDC account management.")
}
@end

View File

@@ -272,7 +272,8 @@ SettingsIdentityServerCoordinatorBridgePresenterDelegate,
ServiceTermsModalCoordinatorBridgePresenterDelegate,
TableViewSectionsDelegate,
ThreadsBetaCoordinatorBridgePresenterDelegate,
ChangePasswordCoordinatorBridgePresenterDelegate>
ChangePasswordCoordinatorBridgePresenterDelegate,
SSOAuthenticationPresenterDelegate>
{
// Current alert (if any).
__weak UIAlertController *currentAlert;
@@ -373,6 +374,8 @@ ChangePasswordCoordinatorBridgePresenterDelegate>
@property (nonatomic) BOOL isPreparingIdentityService;
@property (nonatomic, strong) ServiceTermsModalCoordinatorBridgePresenter *serviceTermsModalCoordinatorBridgePresenter;
@property (nonatomic, strong) SSOAuthenticationPresenter *ssoAuthenticationPresenter;
@property (nonatomic) AnalyticsScreenTracker *screenTracker;
@end
@@ -473,24 +476,29 @@ ChangePasswordCoordinatorBridgePresenterDelegate>
[sectionUserSettings addRowWithTag: USER_SETTINGS_PHONENUMBERS_OFFSET + index];
}
}
if (BWIBuildSettings.shared.settingsScreenAllowAddingEmailThreepids &&
BuildSettings.settingsScreenAllowAddingEmailThreepids &&
// If the threePidChanges is nil we assume the capability to be true
(!self.mainSession.homeserverCapabilities.threePidChanges ||
self.mainSession.homeserverCapabilities.threePidChanges.enabled))
{
[sectionUserSettings addRowWithTag:USER_SETTINGS_ADD_EMAIL_INDEX];
}
if (BWIBuildSettings.shared.settingsScreenAllowAddingPhoneThreepids)
{
[sectionUserSettings addRowWithTag:USER_SETTINGS_ADD_PHONENUMBER_INDEX];
}
if (BWIBuildSettings.shared.settingsScreenShowThreepidExplanatory)
{
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:[VectorL10n settingsThreePidsManagementInformationPart1] attributes:@{}];
[attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:[VectorL10n settingsThreePidsManagementInformationPart2] attributes:@{NSForegroundColorAttributeName: ThemeService.shared.theme.tintColor}]];
[attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:[VectorL10n settingsThreePidsManagementInformationPart3] attributes:@{}]];
sectionUserSettings.attributedFooterTitle = attributedString;
// If the threePidChanges is nil we assume the capability to be true
if (!self.mainSession.homeserverCapabilities.threePidChanges ||
self.mainSession.homeserverCapabilities.threePidChanges.enabled) {
if (BWIBuildSettings.shared.settingsScreenAllowAddingEmailThreepids &&
BuildSettings.settingsScreenAllowAddingEmailThreepids &&
// If the threePidChanges is nil we assume the capability to be true
(!self.mainSession.homeserverCapabilities.threePidChanges ||
self.mainSession.homeserverCapabilities.threePidChanges.enabled))
{
[sectionUserSettings addRowWithTag:USER_SETTINGS_ADD_EMAIL_INDEX];
}
if (BWIBuildSettings.shared.settingsScreenAllowAddingPhoneThreepids)
{
[sectionUserSettings addRowWithTag:USER_SETTINGS_ADD_PHONENUMBER_INDEX];
}
if (BWIBuildSettings.shared.settingsScreenShowThreepidExplanatory)
{
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:[VectorL10n settingsThreePidsManagementInformationPart1] attributes:@{}];
[attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:[VectorL10n settingsThreePidsManagementInformationPart2] attributes:@{NSForegroundColorAttributeName: ThemeService.shared.theme.tintColor}]];
[attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:[VectorL10n settingsThreePidsManagementInformationPart3] attributes:@{}]];
sectionUserSettings.attributedFooterTitle = attributedString;
}
}
sectionUserSettings.headerTitle = [VectorL10n settingsUserSettings];
@@ -4498,7 +4506,12 @@ ChangePasswordCoordinatorBridgePresenterDelegate>
{
NSURL *url = [NSURL URLWithString: self.mainSession.homeserverWellknown.authentication.account];
if (url) {
[UIApplication.sharedApplication openURL:url options:@{} completionHandler:nil];
SSOAccountService *service = [[SSOAccountService alloc] initWithAccountURL:url];
SSOAuthenticationPresenter *presenter = [[SSOAuthenticationPresenter alloc] initWithSsoAuthenticationService:service];
presenter.delegate = self;
self.ssoAuthenticationPresenter = presenter;
[presenter presentForIdentityProvider:nil with:@"" from:self animated:YES];
}
}
@@ -5510,4 +5523,26 @@ ChangePasswordCoordinatorBridgePresenterDelegate>
[self.userSessionsFlowCoordinatorBridgePresenter pushFrom:self.navigationController animated:YES];
}
#pragma mark - SSOAuthenticationPresenterDelegate
- (void)ssoAuthenticationPresenterDidCancel:(SSOAuthenticationPresenter *)presenter
{
self.ssoAuthenticationPresenter = nil;
MXLogDebug(@"OIDC account management complete.")
}
- (void)ssoAuthenticationPresenter:(SSOAuthenticationPresenter *)presenter authenticationDidFailWithError:(NSError *)error
{
self.ssoAuthenticationPresenter = nil;
MXLogError(@"OIDC account management failed.")
}
- (void)ssoAuthenticationPresenter:(SSOAuthenticationPresenter *)presenter
authenticationSucceededWithToken:(NSString *)token
usingIdentityProvider:(SSOIdentityProvider *)identityProvider
{
self.ssoAuthenticationPresenter = nil;
MXLogWarning(@"Unexpected callback after OIDC account management.")
}
@end

View File

@@ -60,6 +60,7 @@ targets:
- path: ../Config/BuM/BWIBuildSettings+BuM.swift
- path: ../bwi/UserAgent/UserAgentService.swift
- path: ../bwi/LoginProtection/LoginProtectionService.swift
- path: ../Config/MDMSettings.swift
- path: ../Riot/Utils/DataProtectionHelper.swift
- path: ../Config/CommonConfiguration.swift
- path: ../Riot/Experiments/

View File

@@ -53,10 +53,11 @@ class ForwardingShareItemSender: NSObject, ShareItemSenderProtocol {
var localEcho: MXEvent?
room.sendMessage(withContent: event.content, threadId: nil, localEcho: &localEcho) { result in
switch result {
case .success(_):
self.trackForwardMessage(room: room)
case .failure(let innerError):
errors.append(innerError)
default:
room.summary.resetLastMessage(nil, failure: nil, commit: false)
break
}
dispatchGroup.leave()
@@ -72,12 +73,4 @@ class ForwardingShareItemSender: NSObject, ShareItemSenderProtocol {
success()
}
}
func trackForwardMessage(room: MXRoom) {
BWIAnalyticsHelper.getRoomDeviceCount(room: room) { deviceCount in
let deviceCountString = BWIAnalyticsHelper.dimensionForDeviceCount(deviceCount)
let messageType = BWIAnalyticsHelper.getForwardingType(event: self.event)
BWIAnalytics.sharedTracker.trackEventWithDimension(category: "Feature", action: "ForwardMessage", dimension: deviceCountString, value: nil, name: messageType)
}
}
}

View File

@@ -36,7 +36,9 @@ typedef NS_ENUM(NSUInteger, ShareManagerResult) {
@property (nonatomic, copy) void (^completionCallback)(ShareManagerResult);
- (instancetype)initWithShareItemSender:(id<ShareItemSenderProtocol>)itemSender
type:(ShareManagerType)type;
type:(ShareManagerType)type
session:(nullable MXSession*)session;
- (UIViewController *)mainViewController;

View File

@@ -31,6 +31,8 @@
@property (nonatomic, strong, readonly) ShareViewController *shareViewController;
@property (nonatomic) BOOL useCustomSession;
@property (nonatomic, strong) MXSession* session;
@property (nonatomic, strong) MXKAccount *userAccount;
@property (nonatomic, strong) MXFileStore *fileStore;
@@ -51,11 +53,14 @@ static MXSession *fakeSession;
- (instancetype)initWithShareItemSender:(id<ShareItemSenderProtocol>)itemSender
type:(ShareManagerType)type
session:(MXSession*)session
{
if (self = [super init])
{
_shareItemSender = itemSender;
_shareItemSender.delegate = self;
_session = session;
_useCustomSession = _session == nil;
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(checkUserAccount) name:kMXKAccountManagerDidRemoveAccountNotification object:nil];
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(checkUserAccount) name:NSExtensionHostWillEnterForegroundNotification object:nil];
@@ -71,7 +76,20 @@ static MXSession *fakeSession;
[NSBundle mxk_setLanguage:language];
[NSBundle mxk_setFallbackLanguage:@"en"];
[self checkUserAccount];
if (!_useCustomSession)
{
// If we don't use a custom session, we can initialize the shareViewController with our existing session
self.userAccount = [MXKAccountManager sharedManager].activeAccounts.firstObject;
ShareDataSource *roomDataSource = [[ShareDataSource alloc] initWithFileStore:_session.store
session:_session];
[self.shareViewController configureWithState:ShareViewControllerAccountStateConfigured
roomDataSource:roomDataSource];
}
else
{
[self checkUserAccount];
}
}
return self;
@@ -95,32 +113,23 @@ static MXSession *fakeSession;
MXStrongifyAndReturnIfNil(self);
[self.userAccount handleUnauthenticatedWithError:error isSoftLogout:isSoftLogout isRefreshTokenAuth:isRefreshTokenAuth andCompletion:completion];
}];
MXSession *session = [[MXSession alloc] initWithMatrixRestClient:restClient];
[MXFileStore setPreloadOptions:0];
MXWeakify(session);
[session setStore:self.fileStore success:^{
MXStrongifyAndReturnIfNil(session);
self.selectedRooms = [NSMutableArray array];
for (NSString *roomIdentifier in roomIdentifiers) {
MXRoom *room = [MXRoom loadRoomFromStore:self.fileStore withRoomId:roomIdentifier matrixSession:session];
if (room) {
[self.selectedRooms addObject:room];
}
}
[self.shareItemSender sendItemsToRooms:self.selectedRooms success:^{
self.selectedRooms = nil;
self.completionCallback(ShareManagerResultFinished);
} failure:^(NSArray<NSError *> *errors) {
self.selectedRooms = nil;
[self showFailureAlert:[VectorL10n roomEventFailedToSend]];
if (self.useCustomSession || !self.session)
{
MXSession* session = [[MXSession alloc] initWithMatrixRestClient:restClient];
[MXFileStore setPreloadOptions:0];
MXWeakify(session);
[session setStore:self.fileStore success:^{
MXStrongifyAndReturnIfNil(session);
[self shareForRoomIdentifiers:roomIdentifiers usingSession:session];
} failure:^(NSError *error) {
MXLogError(@"[ShareManager] Failed preparing matrix session");
}];
} failure:^(NSError *error) {
MXLogError(@"[ShareManager] Failed preparing matrix session");
}];
}
else
{
[self shareForRoomIdentifiers:roomIdentifiers usingSession:self.session];
}
}
- (void)shareViewControllerDidRequestDismissal:(ShareViewController *)shareViewController
@@ -142,6 +151,25 @@ static MXSession *fakeSession;
#pragma mark - Private
- (void)shareForRoomIdentifiers:(NSSet<NSString *> *)roomIdentifiers usingSession:(MXSession*)session
{
self.selectedRooms = [NSMutableArray array];
for (NSString *roomIdentifier in roomIdentifiers) {
MXRoom *room = [MXRoom loadRoomFromStore:session.store withRoomId:roomIdentifier matrixSession:session];
if (room) {
[self.selectedRooms addObject:room];
}
}
[self.shareItemSender sendItemsToRooms:self.selectedRooms success:^{
self.selectedRooms = nil;
self.completionCallback(ShareManagerResultFinished);
} failure:^(NSArray<NSError *> *errors) {
self.selectedRooms = nil;
[self showFailureAlert:[VectorL10n roomEventFailedToSend]];
}];
}
- (void)showFailureAlert:(NSString *)title
{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleAlert];

View File

@@ -54,6 +54,7 @@ targets:
- path: ../Config/BWIBuildSettings.swift
- path: ../Config/BuM/BWIBuildSettings+BuM.swift
- path: ../bwi/UserAgent/UserAgentService.swift
- path: ../Config/MDMSettings.swift
- path: ../Riot/Categories/Character.swift
- path: ../Riot/Categories/MXKImageView.swift
- path: ../Riot/Categories/MXRoom+Riot.m

View File

@@ -32,6 +32,7 @@ final class UserSessionsFlowCoordinator: NSObject, Coordinator, Presentable {
private var errorPresenter: MXKErrorPresentation
private var indicatorPresenter: UserIndicatorTypePresenterProtocol
private var loadingIndicator: UserIndicator?
private var ssoAuthenticationPresenter: SSOAuthenticationPresenter?
/// The root coordinator for user session management.
private weak var sessionsOverviewCoordinator: UserSessionsOverviewCoordinator?
@@ -188,21 +189,25 @@ final class UserSessionsFlowCoordinator: NSObject, Coordinator, Presentable {
private func createOtherSessionsCoordinator(sessionInfos: [UserSessionInfo],
filterBy filter: UserOtherSessionsFilter,
title: String) -> UserOtherSessionsCoordinator {
let shouldShowDeviceLogout = parameters.session.homeserverWellknown.authentication == nil
let parameters = UserOtherSessionsCoordinatorParameters(sessionInfos: sessionInfos,
filter: filter,
title: title)
title: title,
showDeviceLogout: shouldShowDeviceLogout)
return UserOtherSessionsCoordinator(parameters: parameters)
}
private func openDeviceLogoutRedirectURL(_ url: URL) {
let alert = UIAlertController(title: VectorL10n.manageSessionRedirect, message: nil, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: VectorL10n.ok, style: .default) { [weak self] _ in
UIApplication.shared.open(url) { [weak self] success in
guard success else {
return
}
self?.popToSessionsOverview()
}
guard let self else { return }
let service = SSOAccountService(accountURL: url)
let presenter = SSOAuthenticationPresenter(ssoAuthenticationService: service)
presenter.delegate = self
self.ssoAuthenticationPresenter = presenter
presenter.present(forIdentityProvider: nil, with: "", from: self.toPresentable(), animated: true)
})
alert.popoverPresentationController?.sourceView = toPresentable().view
navigationRouter.present(alert, animated: true)
@@ -547,3 +552,25 @@ private extension UserOtherSessionsFilter {
}
}
}
// MARK: ASWebAuthenticationPresentationContextProviding
extension UserSessionsFlowCoordinator: SSOAuthenticationPresenterDelegate {
func ssoAuthenticationPresenterDidCancel(_ presenter: SSOAuthenticationPresenter) {
ssoAuthenticationPresenter = nil
MXLog.info("OIDC account management complete.")
popToSessionsOverview()
}
func ssoAuthenticationPresenter(_ presenter: SSOAuthenticationPresenter, authenticationDidFailWithError error: Error) {
ssoAuthenticationPresenter = nil
MXLog.error("OIDC account management failed.")
}
func ssoAuthenticationPresenter(_ presenter: SSOAuthenticationPresenter,
authenticationSucceededWithToken token: String,
usingIdentityProvider identityProvider: SSOIdentityProvider?) {
ssoAuthenticationPresenter = nil
MXLog.warning("Unexpected callback after OIDC account management.")
}
}

View File

@@ -21,6 +21,7 @@ struct UserOtherSessionsCoordinatorParameters {
let sessionInfos: [UserSessionInfo]
let filter: UserOtherSessionsFilter
let title: String
let showDeviceLogout: Bool
}
final class UserOtherSessionsCoordinator: Coordinator, Presentable {
@@ -40,6 +41,7 @@ final class UserOtherSessionsCoordinator: Coordinator, Presentable {
let viewModel = UserOtherSessionsViewModel(sessionInfos: parameters.sessionInfos,
filter: parameters.filter,
title: parameters.title,
showDeviceLogout: parameters.showDeviceLogout,
settingsService: RiotSettings.shared)
let view = UserOtherSessions(viewModel: viewModel.context)
userOtherSessionsViewModel = viewModel

View File

@@ -49,26 +49,31 @@ enum MockUserOtherSessionsScreenState: MockScreenState, CaseIterable {
viewModel = UserOtherSessionsViewModel(sessionInfos: allSessions(),
filter: .all,
title: VectorL10n.userSessionsOverviewOtherSessionsSectionTitle,
showDeviceLogout: true,
settingsService: MockUserSessionSettings())
case .none:
viewModel = UserOtherSessionsViewModel(sessionInfos: [],
filter: .all,
title: VectorL10n.userSessionsOverviewOtherSessionsSectionTitle,
showDeviceLogout: true,
settingsService: MockUserSessionSettings())
case .inactiveSessions:
viewModel = UserOtherSessionsViewModel(sessionInfos: inactiveSessions(),
filter: .inactive,
title: VectorL10n.userOtherSessionSecurityRecommendationTitle,
showDeviceLogout: true,
settingsService: MockUserSessionSettings())
case .unverifiedSessions:
viewModel = UserOtherSessionsViewModel(sessionInfos: unverifiedSessions(),
filter: .unverified,
title: VectorL10n.userOtherSessionSecurityRecommendationTitle,
showDeviceLogout: true,
settingsService: MockUserSessionSettings())
case .verifiedSessions:
viewModel = UserOtherSessionsViewModel(sessionInfos: verifiedSessions(),
filter: .verified,
title: VectorL10n.userOtherSessionSecurityRecommendationTitle,
showDeviceLogout: true,
settingsService: MockUserSessionSettings())
}

View File

@@ -63,7 +63,8 @@ class UserOtherSessionsViewModelTests: XCTestCase {
emptyItemsTitle: VectorL10n.userOtherSessionNoInactiveSessions,
allItemsSelected: false,
enableSignOutButton: false,
showLocationInfo: false)
showLocationInfo: false,
showDeviceLogout: true)
XCTAssertEqual(sut.state, expectedState)
}
@@ -81,7 +82,8 @@ class UserOtherSessionsViewModelTests: XCTestCase {
emptyItemsTitle: "",
allItemsSelected: false,
enableSignOutButton: false,
showLocationInfo: false)
showLocationInfo: false,
showDeviceLogout: true)
XCTAssertEqual(sut.state, expectedState)
}
@@ -104,7 +106,8 @@ class UserOtherSessionsViewModelTests: XCTestCase {
emptyItemsTitle: VectorL10n.userOtherSessionNoUnverifiedSessions,
allItemsSelected: false,
enableSignOutButton: false,
showLocationInfo: false)
showLocationInfo: false,
showDeviceLogout: true)
XCTAssertEqual(expectedItems.count, 2)
XCTAssertEqual(sut.state, expectedState)
}
@@ -123,7 +126,8 @@ class UserOtherSessionsViewModelTests: XCTestCase {
emptyItemsTitle: VectorL10n.userOtherSessionNoVerifiedSessions,
allItemsSelected: false,
enableSignOutButton: false,
showLocationInfo: false)
showLocationInfo: false,
showDeviceLogout: true)
XCTAssertEqual(sut.state, expectedState)
}
@@ -139,7 +143,8 @@ class UserOtherSessionsViewModelTests: XCTestCase {
emptyItemsTitle: VectorL10n.userOtherSessionNoVerifiedSessions,
allItemsSelected: false,
enableSignOutButton: false,
showLocationInfo: false)
showLocationInfo: false,
showDeviceLogout: true)
XCTAssertEqual(sut.state, expectedState)
}
@@ -155,7 +160,8 @@ class UserOtherSessionsViewModelTests: XCTestCase {
emptyItemsTitle: VectorL10n.userOtherSessionNoUnverifiedSessions,
allItemsSelected: false,
enableSignOutButton: false,
showLocationInfo: false)
showLocationInfo: false,
showDeviceLogout: true)
XCTAssertEqual(sut.state, expectedState)
}
@@ -171,7 +177,8 @@ class UserOtherSessionsViewModelTests: XCTestCase {
emptyItemsTitle: VectorL10n.userOtherSessionNoInactiveSessions,
allItemsSelected: false,
enableSignOutButton: false,
showLocationInfo: false)
showLocationInfo: false,
showDeviceLogout: true)
XCTAssertEqual(sut.state, expectedState)
}
@@ -192,7 +199,8 @@ class UserOtherSessionsViewModelTests: XCTestCase {
emptyItemsTitle: "",
allItemsSelected: true,
enableSignOutButton: true,
showLocationInfo: false)
showLocationInfo: false,
showDeviceLogout: true)
XCTAssertEqual(sut.state, expectedState)
}
@@ -213,7 +221,8 @@ class UserOtherSessionsViewModelTests: XCTestCase {
emptyItemsTitle: "",
allItemsSelected: false,
enableSignOutButton: false,
showLocationInfo: false)
showLocationInfo: false,
showDeviceLogout: true)
XCTAssertEqual(sut.state, expectedState)
}
@@ -233,7 +242,8 @@ class UserOtherSessionsViewModelTests: XCTestCase {
emptyItemsTitle: "",
allItemsSelected: false,
enableSignOutButton: true,
showLocationInfo: false)
showLocationInfo: false,
showDeviceLogout: true)
XCTAssertEqual(sut.state, expectedState)
}
@@ -253,7 +263,8 @@ class UserOtherSessionsViewModelTests: XCTestCase {
emptyItemsTitle: "",
allItemsSelected: true,
enableSignOutButton: true,
showLocationInfo: false)
showLocationInfo: false,
showDeviceLogout: true)
XCTAssertEqual(sut.state, expectedState)
}
@@ -273,7 +284,8 @@ class UserOtherSessionsViewModelTests: XCTestCase {
emptyItemsTitle: "",
allItemsSelected: false,
enableSignOutButton: false,
showLocationInfo: false)
showLocationInfo: false,
showDeviceLogout: true)
XCTAssertEqual(sut.state, expectedState)
}
@@ -296,7 +308,8 @@ class UserOtherSessionsViewModelTests: XCTestCase {
emptyItemsTitle: "",
allItemsSelected: false,
enableSignOutButton: false,
showLocationInfo: false)
showLocationInfo: false,
showDeviceLogout: true)
XCTAssertEqual(sut.state, expectedState)
}
@@ -352,6 +365,7 @@ class UserOtherSessionsViewModelTests: XCTestCase {
UserOtherSessionsViewModel(sessionInfos: sessionInfos,
filter: filter,
title: title,
showDeviceLogout: true,
settingsService: MockUserSessionSettings())
}

View File

@@ -43,6 +43,7 @@ struct UserOtherSessionsViewState: BindableState, Equatable {
var allItemsSelected: Bool
var enableSignOutButton: Bool
var showLocationInfo: Bool
var showDeviceLogout: Bool
}
struct UserOtherSessionsBindings: Equatable {

View File

@@ -28,6 +28,7 @@ class UserOtherSessionsViewModel: UserOtherSessionsViewModelType, UserOtherSessi
init(sessionInfos: [UserSessionInfo],
filter: UserOtherSessionsFilter,
title: String,
showDeviceLogout: Bool,
settingsService: UserSessionSettingsProtocol) {
self.sessionInfos = sessionInfos
defaultTitle = title
@@ -41,7 +42,8 @@ class UserOtherSessionsViewModel: UserOtherSessionsViewModelType, UserOtherSessi
emptyItemsTitle: filter.userOtherSessionsViewEmptyResultsTitle,
allItemsSelected: false,
enableSignOutButton: false,
showLocationInfo: settingsService.showIPAddressesInSessionsManager))
showLocationInfo: settingsService.showIPAddressesInSessionsManager,
showDeviceLogout: showDeviceLogout))
}
// MARK: - Public

View File

@@ -60,6 +60,7 @@ struct UserOtherSessions: View {
set: { _ in withAnimation { viewModel.send(viewAction: .showLocationInfo) } }),
allItemsSelected: viewModel.viewState.allItemsSelected,
sessionCount: viewModel.viewState.sessionItems.count,
showDeviceLogout: viewModel.viewState.showDeviceLogout,
onToggleSelection: { viewModel.send(viewAction: .toggleAllSelection) },
onSignOut: { viewModel.send(viewAction: .logoutAllUserSessions) })
}

View File

@@ -24,6 +24,7 @@ struct UserOtherSessionsToolbar: ToolbarContent {
@Binding var isShowLocationEnabled: Bool
let allItemsSelected: Bool
let sessionCount: Int
let showDeviceLogout: Bool
let onToggleSelection: () -> Void
let onSignOut: () -> Void
@@ -87,12 +88,14 @@ struct UserOtherSessionsToolbar: ToolbarContent {
private func optionsMenu() -> some View {
Button { } label: {
Menu {
Button {
isEditModeEnabled = true
} label: {
Label(VectorL10n.userOtherSessionMenuSelectSessions, systemImage: "checkmark.circle")
if showDeviceLogout { // As you can only sign out the selected sessions, we don't allow selection when you're unable to sign out devices.
Button {
isEditModeEnabled = true
} label: {
Label(VectorL10n.userOtherSessionMenuSelectSessions, systemImage: "checkmark.circle")
}
.disabled(sessionCount == 0)
}
.disabled(sessionCount == 0)
if BWIBuildSettings.shared.deviceManagerShowIPAddress {
Button {
@@ -102,7 +105,7 @@ struct UserOtherSessionsToolbar: ToolbarContent {
}
}
if sessionCount > 0 {
if sessionCount > 0, showDeviceLogout {
DestructiveButton {
onSignOut()
} label: {

View File

@@ -39,7 +39,10 @@ final class UserSessionsOverviewCoordinator: Coordinator, Presentable {
self.parameters = parameters
service = parameters.service
viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: parameters.service, settingsService: RiotSettings.shared)
let shouldShowDeviceLogout = parameters.session.homeserverWellknown.authentication == nil
viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: parameters.service,
settingsService: RiotSettings.shared,
showDeviceLogout: shouldShowDeviceLogout)
hostingViewController = VectorHostingController(rootView: UserSessionsOverview(viewModel: viewModel.context))
hostingViewController.vc_setLargeTitleDisplayMode(.never)

View File

@@ -51,7 +51,7 @@ enum MockUserSessionsOverviewScreenState: MockScreenState, CaseIterable {
fatalError()
}
let viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: service, settingsService: MockUserSessionSettings())
let viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: service, settingsService: MockUserSessionSettings(), showDeviceLogout: true)
return (
[service, viewModel],

View File

@@ -21,7 +21,9 @@ import XCTest
class UserSessionsOverviewViewModelTests: XCTestCase {
func testInitialStateEmpty() {
let viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: MockUserSessionsOverviewService(), settingsService: MockUserSessionSettings())
let viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: MockUserSessionsOverviewService(),
settingsService: MockUserSessionSettings(),
showDeviceLogout: true)
XCTAssertNil(viewModel.state.currentSessionViewData)
XCTAssertTrue(viewModel.state.unverifiedSessionsViewData.isEmpty)
@@ -31,7 +33,9 @@ class UserSessionsOverviewViewModelTests: XCTestCase {
}
func testLoadOnDidAppear() {
let viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: MockUserSessionsOverviewService(), settingsService: MockUserSessionSettings())
let viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: MockUserSessionsOverviewService(),
settingsService: MockUserSessionSettings(),
showDeviceLogout: true)
viewModel.process(viewAction: .viewAppeared)
XCTAssertNotNil(viewModel.state.currentSessionViewData)
@@ -42,7 +46,9 @@ class UserSessionsOverviewViewModelTests: XCTestCase {
}
func testSimpleActionProcessing() {
let viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: MockUserSessionsOverviewService(), settingsService: MockUserSessionSettings())
let viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: MockUserSessionsOverviewService(),
settingsService: MockUserSessionSettings(),
showDeviceLogout: true)
var result: UserSessionsOverviewViewModelResult?
viewModel.completion = { action in
@@ -69,7 +75,9 @@ class UserSessionsOverviewViewModelTests: XCTestCase {
let service = MockUserSessionsOverviewService()
service.updateOverviewData { _ in }
let viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: service, settingsService: MockUserSessionSettings())
let viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: service,
settingsService: MockUserSessionSettings(),
showDeviceLogout: true)
var result: UserSessionsOverviewViewModelResult?
viewModel.completion = { action in

View File

@@ -51,6 +51,7 @@ struct UserSessionsOverviewViewState: BindableState {
var showLoadingIndicator = false
var linkDeviceButtonVisible = false
var showLocationInfo: Bool
var showDeviceLogout: Bool
}
enum UserSessionsOverviewViewAction {

View File

@@ -24,11 +24,11 @@ class UserSessionsOverviewViewModel: UserSessionsOverviewViewModelType, UserSess
var completion: ((UserSessionsOverviewViewModelResult) -> Void)?
init(userSessionsOverviewService: UserSessionsOverviewServiceProtocol, settingsService: UserSessionSettingsProtocol) {
init(userSessionsOverviewService: UserSessionsOverviewServiceProtocol, settingsService: UserSessionSettingsProtocol, showDeviceLogout: Bool) {
self.userSessionsOverviewService = userSessionsOverviewService
self.settingsService = settingsService
let showLocationInfo = BWIBuildSettings.shared.deviceManagerShowIPAddress && settingsService.showIPAddressesInSessionsManager
super.init(initialViewState: .init(showLocationInfo: showLocationInfo))
super.init(initialViewState: .init(showLocationInfo: showLocationInfo, showDeviceLogout: showDeviceLogout))
userSessionsOverviewService.overviewDataPublisher.sink { [weak self] overviewData in
self?.updateViewState(with: overviewData)

View File

@@ -125,7 +125,7 @@ struct UserSessionsOverview: View {
Label(VectorL10n.signOut, systemImage: "rectangle.portrait.and.arrow.right.fill")
}
}
if viewModel.viewState.otherSessionsViewData.count > 0 {
if viewModel.viewState.otherSessionsViewData.count > 0, viewModel.viewState.showDeviceLogout {
DestructiveButton {
viewModel.send(viewAction: .logoutOtherSessions)
} label: {
@@ -141,19 +141,20 @@ struct UserSessionsOverview: View {
private var otherSessionsMenu: some View {
Menu {
if BWIBuildSettings.shared.deviceManagerShowIPAddress {
Button {
withAnimation {
viewModel.send(viewAction: .showLocationInfo)
}
} label: {
Label(showLocationInfo: viewModel.viewState.showLocationInfo)
Button {
withAnimation {
viewModel.send(viewAction: .showLocationInfo)
}
}
DestructiveButton {
viewModel.send(viewAction: .logoutOtherSessions)
} label: {
Label(VectorL10n.userOtherSessionMenuSignOutSessions(String(viewModel.viewState.otherSessionsViewData.count)), systemImage: "rectangle.portrait.and.arrow.forward.fill")
Label(showLocationInfo: viewModel.viewState.showLocationInfo)
}
if viewModel.viewState.showDeviceLogout {
DestructiveButton {
viewModel.send(viewAction: .logoutOtherSessions)
} label: {
Label(VectorL10n.userOtherSessionMenuSignOutSessions(String(viewModel.viewState.otherSessionsViewData.count)), systemImage: "rectangle.portrait.and.arrow.forward.fill")
}
}
} label: {
menuImage

View File

@@ -55,6 +55,7 @@ targets:
- path: ../Config/BuildSettings.swift
- path: ../Config/BWIBuildSettings.swift
- path: ../Config/BuM/BWIBuildSettings+BuM.swift
- path: ../Config/MDMSettings.swift
- path: ../Riot/Modules/Room/TimelineCells/Styles/RoomTimelineStyleIdentifier.swift
- path: ../Riot/Categories/String.swift
- path: ../Riot/Categories/Character.swift

View File

@@ -64,6 +64,7 @@ targets:
- path: ../Config/BuildSettings.swift
- path: ../Config/BWIBuildSettings.swift
- path: ../Config/BuM/BWIBuildSettings+BuM.swift
- path: ../Config/MDMSettings.swift
- path: ../Riot/Modules/Room/TimelineCells/Styles/RoomTimelineStyleIdentifier.swift
- path: ../Riot/Categories/String.swift
- path: ../Riot/Categories/Character.swift

View File

@@ -65,6 +65,7 @@ targets:
- path: ../Config/BuM/BWIBuildSettings+BuM.swift
- path: ../Config/AppConfiguration.swift
- path: ../Config/CommonConfiguration.swift
- path: ../Config/MDMSettings.swift
- path: ../Riot/Categories/Bundle.swift
- path: ../Riot/Managers/AppInfo/AppInfo.swift
- path: ../Riot/Managers/AppInfo/AppVersion.swift

View File

@@ -50,6 +50,7 @@ targets:
- path: ../Config/BuildSettings.swift
- path: ../Config/BWIBuildSettings.swift
- path: ../Config/BuM/BWIBuildSettings+BuM.swift
- path: ../Config/MDMSettings.swift
- path: ../Config/Configurable.swift
- path: ../Riot/Managers/Settings/RiotSettings.swift
- path: ../Riot/Managers/EncryptionKeyManager/EncryptionKeyManager.swift