Show an alert when entering an account provider that requires Element Pro. (#4326)

This commit is contained in:
Doug
2025-07-17 13:41:26 +01:00
committed by GitHub
parent 247c7a4617
commit f655fbc28b
30 changed files with 253 additions and 5 deletions
@@ -14,6 +14,7 @@ struct LoginScreenCoordinatorParameters {
/// An optional hint that can be used to pre-fill the form.
let loginHint: String?
let userIndicatorController: UserIndicatorControllerProtocol
let appSettings: AppSettings
let analytics: AnalyticsService
}
@@ -46,6 +47,7 @@ final class LoginScreenCoordinator: CoordinatorProtocol {
viewModel = LoginScreenViewModel(authenticationService: parameters.authenticationService,
loginHint: parameters.loginHint,
userIndicatorController: parameters.userIndicatorController,
appSettings: parameters.appSettings,
analytics: parameters.analytics)
}
@@ -70,6 +70,8 @@ enum LoginScreenErrorType: Hashable {
case invalidWellKnownAlert(String)
/// An alert that allows the user to learn about sliding sync.
case slidingSyncAlert
/// An alert that informs the user that Element Pro should be used for a particular server.
case elementProAlert
/// An alert that informs the user that login failed due to a refresh token being returned.
case refreshTokenAlert
/// The response from the homeserver was unexpected.
@@ -13,6 +13,7 @@ typealias LoginScreenViewModelType = StateStoreViewModelV2<LoginScreenViewState,
class LoginScreenViewModel: LoginScreenViewModelType, LoginScreenViewModelProtocol {
private let authenticationService: AuthenticationServiceProtocol
private let userIndicatorController: UserIndicatorControllerProtocol
private let appSettings: AppSettings
private let analytics: AnalyticsService
private var actionsSubject: PassthroughSubject<LoginScreenViewModelAction, Never> = .init()
@@ -23,9 +24,11 @@ class LoginScreenViewModel: LoginScreenViewModelType, LoginScreenViewModelProtoc
init(authenticationService: AuthenticationServiceProtocol,
loginHint: String?,
userIndicatorController: UserIndicatorControllerProtocol,
appSettings: AppSettings,
analytics: AnalyticsService) {
self.authenticationService = authenticationService
self.userIndicatorController = userIndicatorController
self.appSettings = appSettings
self.analytics = analytics
let username = switch loginHint {
@@ -146,6 +149,16 @@ class LoginScreenViewModel: LoginScreenViewModelType, LoginScreenViewModelProtoc
// Clear out the invalid username to avoid an attempted login to matrix.org
state.bindings.username = ""
case .elementProRequired(let serverName):
state.bindings.alertInfo = AlertInfo(id: .elementProAlert,
title: L10n.screenChangeServerErrorElementProRequiredTitle,
message: L10n.screenChangeServerErrorElementProRequiredMessage(serverName),
primaryButton: .init(title: L10n.screenChangeServerErrorElementProRequiredActionIos) {
UIApplication.shared.open(self.appSettings.elementProAppStoreURL)
},
secondaryButton: .init(title: L10n.actionCancel, role: .cancel, action: nil))
// Clear out the invalid username to avoid an attempted login to matrix.org
state.bindings.username = ""
case .sessionTokenRefreshNotSupported:
state.bindings.alertInfo = AlertInfo(id: .refreshTokenAlert,
title: L10n.commonServerNotSupported,
@@ -159,6 +159,7 @@ struct LoginScreen_Previews: PreviewProvider, TestablePreview {
let viewModel = LoginScreenViewModel(authenticationService: authenticationService,
loginHint: nil,
userIndicatorController: UserIndicatorControllerMock(),
appSettings: ServiceLocator.shared.settings,
analytics: ServiceLocator.shared.analytics)
if withCredentials {
@@ -40,6 +40,7 @@ final class ServerConfirmationScreenCoordinator: CoordinatorProtocol {
viewModel = ServerConfirmationScreenViewModel(authenticationService: parameters.authenticationService,
mode: mode,
authenticationFlow: parameters.authenticationFlow,
appSettings: parameters.appSettings,
userIndicatorController: parameters.userIndicatorController)
}
@@ -94,6 +94,8 @@ enum ServerConfirmationScreenAlert: Hashable {
case login
/// An alert that informs the user that registration isn't supported.
case registration
/// An alert that informs the user that Element Pro should be used for a particular server.
case elementProRequired(serverName: String)
/// An unknown error has occurred.
case unknownError
}
@@ -13,6 +13,7 @@ typealias ServerConfirmationScreenViewModelType = StateStoreViewModelV2<ServerCo
class ServerConfirmationScreenViewModel: ServerConfirmationScreenViewModelType, ServerConfirmationScreenViewModelProtocol {
let authenticationService: AuthenticationServiceProtocol
let authenticationFlow: AuthenticationFlow
let appSettings: AppSettings
let userIndicatorController: UserIndicatorControllerProtocol
private var actionsSubject: PassthroughSubject<ServerConfirmationScreenViewModelAction, Never> = .init()
@@ -24,9 +25,11 @@ class ServerConfirmationScreenViewModel: ServerConfirmationScreenViewModelType,
init(authenticationService: AuthenticationServiceProtocol,
mode: ServerConfirmationScreenMode,
authenticationFlow: AuthenticationFlow,
appSettings: AppSettings,
userIndicatorController: UserIndicatorControllerProtocol) {
self.authenticationService = authenticationService
self.authenticationFlow = authenticationFlow
self.appSettings = appSettings
self.userIndicatorController = userIndicatorController
let pickerSelection: String? = switch mode {
@@ -94,6 +97,8 @@ class ServerConfirmationScreenViewModel: ServerConfirmationScreenViewModelType,
displayError(.login)
case .registrationNotSupported:
displayError(.registration)
case .elementProRequired(let serverName):
displayError(.elementProRequired(serverName: serverName))
default:
displayError(.unknownError)
}
@@ -184,6 +189,14 @@ class ServerConfirmationScreenViewModel: ServerConfirmationScreenViewModelType,
state.bindings.alertInfo = AlertInfo(id: .registration,
title: L10n.commonServerNotSupported,
message: L10n.errorAccountCreationNotPossible)
case .elementProRequired(let serverName):
state.bindings.alertInfo = AlertInfo(id: .elementProRequired(serverName: serverName),
title: L10n.screenChangeServerErrorElementProRequiredTitle,
message: L10n.screenChangeServerErrorElementProRequiredMessage(serverName),
primaryButton: .init(title: L10n.screenChangeServerErrorElementProRequiredActionIos) {
UIApplication.shared.open(self.appSettings.elementProAppStoreURL)
},
secondaryButton: .init(title: L10n.actionCancel, role: .cancel, action: nil))
case .unknownError:
state.bindings.alertInfo = AlertInfo(id: .unknownError)
}
@@ -162,6 +162,7 @@ struct ServerConfirmationScreen_Previews: PreviewProvider, TestablePreview {
ServerConfirmationScreenViewModel(authenticationService: AuthenticationService.mock,
mode: mode,
authenticationFlow: flow,
appSettings: ServiceLocator.shared.settings,
userIndicatorController: UserIndicatorControllerMock())
}
}
@@ -12,6 +12,7 @@ struct ServerSelectionScreenCoordinatorParameters {
/// The service used to authenticate the user.
let authenticationService: AuthenticationServiceProtocol
let authenticationFlow: AuthenticationFlow
let appSettings: AppSettings
let userIndicatorController: UserIndicatorControllerProtocol
}
@@ -38,6 +39,7 @@ final class ServerSelectionScreenCoordinator: CoordinatorProtocol {
self.parameters = parameters
viewModel = ServerSelectionScreenViewModel(authenticationService: parameters.authenticationService,
authenticationFlow: parameters.authenticationFlow,
appSettings: parameters.appSettings,
userIndicatorController: parameters.userIndicatorController)
userIndicatorController = parameters.userIndicatorController
}
@@ -66,4 +66,6 @@ enum ServerSelectionScreenErrorType: Hashable {
case loginAlert
/// An alert that informs the user that registration isn't supported.
case registrationAlert
/// An alert that informs the user that Element Pro should be used for a particular server.
case elementProAlert
}
@@ -13,6 +13,7 @@ typealias ServerSelectionScreenViewModelType = StateStoreViewModelV2<ServerSelec
class ServerSelectionScreenViewModel: ServerSelectionScreenViewModelType, ServerSelectionScreenViewModelProtocol {
private let authenticationService: AuthenticationServiceProtocol
private let authenticationFlow: AuthenticationFlow
private let appSettings: AppSettings
private let userIndicatorController: UserIndicatorControllerProtocol
private var actionsSubject: PassthroughSubject<ServerSelectionScreenViewModelAction, Never> = .init()
@@ -23,9 +24,11 @@ class ServerSelectionScreenViewModel: ServerSelectionScreenViewModelType, Server
init(authenticationService: AuthenticationServiceProtocol,
authenticationFlow: AuthenticationFlow,
appSettings: AppSettings,
userIndicatorController: UserIndicatorControllerProtocol) {
self.authenticationService = authenticationService
self.authenticationFlow = authenticationFlow
self.appSettings = appSettings
self.userIndicatorController = userIndicatorController
let bindings = ServerSelectionScreenBindings(homeserverAddress: authenticationService.homeserver.value.address)
@@ -96,6 +99,14 @@ class ServerSelectionScreenViewModel: ServerSelectionScreenViewModelType, Server
state.bindings.alertInfo = AlertInfo(id: .registrationAlert,
title: L10n.commonServerNotSupported,
message: L10n.errorAccountCreationNotPossible)
case .elementProRequired(let serverName):
state.bindings.alertInfo = AlertInfo(id: .elementProAlert,
title: L10n.screenChangeServerErrorElementProRequiredTitle,
message: L10n.screenChangeServerErrorElementProRequiredMessage(serverName),
primaryButton: .init(title: L10n.screenChangeServerErrorElementProRequiredActionIos) {
UIApplication.shared.open(self.appSettings.elementProAppStoreURL)
},
secondaryButton: .init(title: L10n.actionCancel, role: .cancel, action: nil))
default:
showFooterMessage(L10n.errorUnknown)
}
@@ -115,6 +115,7 @@ struct ServerSelection_Previews: PreviewProvider, TestablePreview {
let viewModel = ServerSelectionScreenViewModel(authenticationService: authenticationService,
authenticationFlow: .login,
appSettings: ServiceLocator.shared.settings,
userIndicatorController: UserIndicatorControllerMock())
viewModel.context.homeserverAddress = homeserverAddress
if homeserverAddress == "thisisbad" {