diff --git a/CHANGES.md b/CHANGES.md index 717770810..53b527969 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,16 @@ +## Changes in 1.8.6 (2022-03-14) + +🙌 Improvements + +- Upgrade MatrixSDK version ([v0.22.6](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.22.6)). +- Room: Ignore the sender of a room invite without needing to join the room first ([#5807](https://github.com/vector-im/element-ios/issues/5807)) + +🐛 Bugfixes + +- Activity Indicators: Do not show user indicators when the view controller is not visible ([#5801](https://github.com/vector-im/element-ios/issues/5801)) +- Authentication: Fix social login buttons visibility during registration flow and other minor navigation tweaks. ([#5879](https://github.com/vector-im/element-ios/issues/5879)) + + ## Changes in 1.8.5 (2022-03-09) 🐛 Bugfixes diff --git a/Config/AppVersion.xcconfig b/Config/AppVersion.xcconfig index b0402b34e..174e0bd5b 100644 --- a/Config/AppVersion.xcconfig +++ b/Config/AppVersion.xcconfig @@ -15,5 +15,5 @@ // // Version -MARKETING_VERSION = 1.8.5 -CURRENT_PROJECT_VERSION = 1.8.5 +MARKETING_VERSION = 1.8.6 +CURRENT_PROJECT_VERSION = 1.8.6 diff --git a/Podfile b/Podfile index 67f463d93..07fe178d6 100644 --- a/Podfile +++ b/Podfile @@ -13,7 +13,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.22.5' +$matrixSDKVersion = '= 0.22.6' # $matrixSDKVersion = :local # $matrixSDKVersion = { :branch => 'develop'} # $matrixSDKVersion = { :specHash => { git: 'https://git.io/fork123', branch: 'fix' } } diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index ef355b183..9d6727dbb 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -497,6 +497,7 @@ Tap the + to start adding people."; "room_preview_unlinked_email_warning" = "This invitation was sent to %@, which is not associated with this account. You may wish to login with a different account, or add this email to your account."; "room_preview_try_join_an_unknown_room" = "You are trying to access %@. Would you like to join in order to participate in the discussion?"; "room_preview_try_join_an_unknown_room_default" = "a room"; +"room_preview_decline_invitation_options" = "Do you want to decline the invitation or ignore this user?"; // Settings "settings_title" = "Settings"; @@ -2032,6 +2033,7 @@ Tap the + to start adding people."; "end_call" = "End Call"; "resume_call" = "Resume"; "ignore" = "Ignore"; +"ignore_user" = "Ignore User"; "unignore" = "Unignore"; // Events formatter diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 755555512..cf2c25d68 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -2127,6 +2127,10 @@ public class VectorL10n: NSObject { public static var ignore: String { return VectorL10n.tr("Vector", "ignore") } + /// Ignore User + public static var ignoreUser: String { + return VectorL10n.tr("Vector", "ignore_user") + } /// Take photo public static var imagePickerActionCamera: String { return VectorL10n.tr("Vector", "image_picker_action_camera") @@ -5323,6 +5327,10 @@ public class VectorL10n: NSObject { public static var roomPredecessorLink: String { return VectorL10n.tr("Vector", "room_predecessor_link") } + /// Do you want to decline the invitation or ignore this user? + public static var roomPreviewDeclineInvitationOptions: String { + return VectorL10n.tr("Vector", "room_preview_decline_invitation_options") + } /// You have been invited to join this room by %@ public static func roomPreviewInvitationFormat(_ p1: String) -> String { return VectorL10n.tr("Vector", "room_preview_invitation_format", p1) diff --git a/Riot/Modules/Authentication/AuthenticationCoordinator.swift b/Riot/Modules/Authentication/AuthenticationCoordinator.swift index f9d8787aa..e452d8529 100644 --- a/Riot/Modules/Authentication/AuthenticationCoordinator.swift +++ b/Riot/Modules/Authentication/AuthenticationCoordinator.swift @@ -43,6 +43,13 @@ final class AuthenticationCoordinator: NSObject, AuthenticationCoordinatorProtoc var childCoordinators: [Coordinator] = [] var completion: ((AuthenticationCoordinatorResult) -> Void)? + var customServerFieldsVisible = false { + didSet { + guard customServerFieldsVisible != oldValue else { return } + authenticationViewController.setCustomServerFieldsVisible(customServerFieldsVisible) + } + } + // MARK: - Setup init(parameters: AuthenticationCoordinatorParameters) { @@ -74,10 +81,6 @@ final class AuthenticationCoordinator: NSObject, AuthenticationCoordinatorProtoc authenticationViewController.authType = authenticationType } - func showCustomServer() { - authenticationViewController.setCustomServerFieldsVisible(true) - } - func update(externalRegistrationParameters: [AnyHashable: Any]) { authenticationViewController.externalRegistrationParameters = externalRegistrationParameters } diff --git a/Riot/Modules/Authentication/AuthenticationCoordinatorProtocol.swift b/Riot/Modules/Authentication/AuthenticationCoordinatorProtocol.swift index f04676861..54696e503 100644 --- a/Riot/Modules/Authentication/AuthenticationCoordinatorProtocol.swift +++ b/Riot/Modules/Authentication/AuthenticationCoordinatorProtocol.swift @@ -36,12 +36,12 @@ enum AuthenticationCoordinatorResult { protocol AuthenticationCoordinatorProtocol: Coordinator, Presentable { var completion: ((AuthenticationCoordinatorResult) -> Void)? { get set } + /// Whether the custom homeserver checkbox is enabled for the user to enter a homeserver URL. + var customServerFieldsVisible: Bool { get set } + /// Update the screen to display registration or login. func update(authenticationType: MXKAuthenticationType) - /// Enable the custom server checkbox to allow the user to enter a homeserver URL. - func showCustomServer() - /// Force a registration process based on a predefined set of parameters from a server provisioning link. /// For more information see `AuthenticationViewController.externalRegistrationParameters`. func update(externalRegistrationParameters: [AnyHashable: Any]) diff --git a/Riot/Modules/Authentication/AuthenticationViewController.m b/Riot/Modules/Authentication/AuthenticationViewController.m index 449276f09..448d75b8b 100644 --- a/Riot/Modules/Authentication/AuthenticationViewController.m +++ b/Riot/Modules/Authentication/AuthenticationViewController.m @@ -504,6 +504,7 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; // Remove the potential back button. self.navigationItem.leftBarButtonItem = nil; + [self.navigationItem setHidesBackButton:YES]; } else { @@ -903,6 +904,12 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; authInputsview.thirdPartyIdentifiersHidden = YES; [self updateRegistrationScreenWithThirdPartyIdentifiersHidden:YES]; + + // Show the social login buttons again if needed. + [self updateSocialLoginViewVisibility]; + + // Allow backward navigation in the flow again. + [self.navigationItem setHidesBackButton:NO]; } } else if (sender == self.submitButton) @@ -947,7 +954,10 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; else { [self.authenticationActivityIndicator stopAnimating]; - + + // Hide the social login buttons now that a different flow has started. + [self hideSocialLoginView]; + // Show the supported 3rd party ids which may be added to the account authInputsview.thirdPartyIdentifiersHidden = NO; [self updateRegistrationScreenWithThirdPartyIdentifiersHidden:NO]; diff --git a/Riot/Modules/Common/ActivityIndicator/UserIndicatorPresenterWrapper.swift b/Riot/Modules/Common/ActivityIndicator/UserIndicatorPresenterWrapper.swift index f7faa03f6..7d1bd9d3b 100644 --- a/Riot/Modules/Common/ActivityIndicator/UserIndicatorPresenterWrapper.swift +++ b/Riot/Modules/Common/ActivityIndicator/UserIndicatorPresenterWrapper.swift @@ -30,21 +30,23 @@ import CommonKit self.presenter = presenter } - @objc func presentActivityIndicator() { - presentActivityIndicator(label: VectorL10n.homeSyncing) + @objc func presentLoadingIndicator() { + presentLoadingIndicator(label: VectorL10n.homeSyncing) } - @objc func presentActivityIndicator(label: String) { + @objc func presentLoadingIndicator(label: String) { guard loadingIndicator == nil else { - // The app is very liberal with calling `presentActivityIndicator` (often not matched by corresponding `removeCurrentActivityIndicator`), + // The app is very liberal with calling `presentLoadingIndicator` (often not matched by corresponding `dismissLoadingIndicator`), // so there is no reason to keep adding new indiciators if there is one already showing. return } + MXLog.debug("[UserIndicatorPresenterWrapper] Present loading indicator") loadingIndicator = presenter.present(.loading(label: label, isInteractionBlocking: false)) } - @objc func dismissActivityIndicator() { + @objc func dismissLoadingIndicator() { + MXLog.debug("[UserIndicatorPresenterWrapper] Dismiss loading indicator") loadingIndicator = nil } diff --git a/Riot/Modules/Common/Recents/RecentsViewController.m b/Riot/Modules/Common/Recents/RecentsViewController.m index 99c348b1c..dab50e315 100644 --- a/Riot/Modules/Common/Recents/RecentsViewController.m +++ b/Riot/Modules/Common/Recents/RecentsViewController.m @@ -64,6 +64,9 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro // when the user selects it. UISearchBar *tableSearchBar; + // Flag indicating whether the view controller is (at least partially) visible and not dissapearing + BOOL isViewVisible; + // Observe kThemeServiceDidChangeThemeNotification to handle user interface theme change. __weak id kThemeServiceDidChangeThemeNotificationObserver; } @@ -264,6 +267,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; + isViewVisible = YES; [self.screenTracker trackScreen]; @@ -301,6 +305,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; + isViewVisible = NO; // Leave potential editing mode [self cancelEditionMode:NO]; @@ -2408,16 +2413,16 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro } - (void)startActivityIndicatorWithLabel:(NSString *)label { - if (self.indicatorPresenter) { - [self.indicatorPresenter presentActivityIndicatorWithLabel:label]; + if (self.indicatorPresenter && isViewVisible) { + [self.indicatorPresenter presentLoadingIndicatorWithLabel:label]; } else { [super startActivityIndicator]; } } - (void)startActivityIndicator { - if (self.indicatorPresenter) { - [self.indicatorPresenter presentActivityIndicator]; + if (self.indicatorPresenter && isViewVisible) { + [self.indicatorPresenter presentLoadingIndicator]; } else { [super startActivityIndicator]; } @@ -2425,7 +2430,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro - (void)stopActivityIndicator { if (self.indicatorPresenter) { - [self.indicatorPresenter dismissActivityIndicator]; + [self.indicatorPresenter dismissLoadingIndicator]; } else { [super stopActivityIndicator]; } diff --git a/Riot/Modules/Onboarding/OnboardingCoordinator.swift b/Riot/Modules/Onboarding/OnboardingCoordinator.swift index 94182fa56..dd2a379ba 100644 --- a/Riot/Modules/Onboarding/OnboardingCoordinator.swift +++ b/Riot/Modules/Onboarding/OnboardingCoordinator.swift @@ -215,9 +215,7 @@ final class OnboardingCoordinator: NSObject, OnboardingCoordinatorProtocol { coordinator.update(externalRegistrationParameters: externalRegistrationParameters) } - if useCaseResult == .customServer { - coordinator.showCustomServer() - } + coordinator.customServerFieldsVisible = useCaseResult == .customServer if let softLogoutCredentials = parameters.softLogoutCredentials { coordinator.update(softLogoutCredentials: softLogoutCredentials) diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index 8288c6f81..d8a02a9ae 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -567,7 +567,9 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; isAppeared = NO; [VoiceMessageMediaServiceProvider.sharedProvider pauseAllServices]; - [self stopActivityIndicator]; + + // Stop the loading indicator even if the session is still in progress + [self stopLoadingUserIndicator]; } - (void)viewDidAppear:(BOOL)animated @@ -935,10 +937,14 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; self.updateRoomReadMarker = NO; } +#pragma mark - Loading indicators + - (BOOL)providesCustomActivityIndicator { return [self.delegate roomViewControllerCanDelegateUserIndicators:self]; } +// Override of a legacy method to determine whether to use a newer implementation instead. +// Will be removed in the future https://github.com/vector-im/element-ios/issues/5608 - (void)startActivityIndicator { if ([self providesCustomActivityIndicator]) { [self.delegate roomViewControllerDidStartLoading:self]; @@ -947,6 +953,8 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; } } +// Override of a legacy method to determine whether to use a newer implementation instead. +// Will be removed in the future https://github.com/vector-im/element-ios/issues/5608 - (void)stopActivityIndicator { if (notificationTaskProfile) @@ -956,14 +964,22 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; notificationTaskProfile = nil; } if ([self providesCustomActivityIndicator]) { + // The legacy super implementation of `stopActivityIndicator` contains a number of checks grouped under `canStopActivityIndicator` + // to determine whether the indicator can be stopped or not (and the method should thus rather be called `stopActivityIndicatorIfPossible`). + // Since the newer indicators are not calling super implementation, the check for `canStopActivityIndicator` has to be performed manually. if ([self canStopActivityIndicator]) { - [self.delegate roomViewControllerDidStopLoading:self]; + [self stopLoadingUserIndicator]; } } else { [super stopActivityIndicator]; } } +- (void)stopLoadingUserIndicator +{ + [self.delegate roomViewControllerDidStopLoading:self]; +} + - (void)displayRoom:(MXKRoomDataSource *)dataSource { // Remove potential preview Data @@ -4963,10 +4979,32 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; } else if (tappedView == previewHeader.leftButton) { - [self declineRoomInvitation]; + [self presentDeclineOptionsFromView:tappedView]; } } +- (void)presentDeclineOptionsFromView:(UIView *)view +{ + UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:[VectorL10n roomPreviewDeclineInvitationOptions] + message:nil + preferredStyle:UIAlertControllerStyleActionSheet]; + [actionSheet addAction:[UIAlertAction actionWithTitle:[VectorL10n decline] + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * _Nonnull action) { + [self declineRoomInvitation]; + }]]; + [actionSheet addAction:[UIAlertAction actionWithTitle:[VectorL10n ignoreUser] + style:UIAlertActionStyleDestructive + handler:^(UIAlertAction * _Nonnull action) { + [self ignoreInviteSender]; + }]]; + [actionSheet addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel] + style:UIAlertActionStyleCancel + handler:nil]]; + actionSheet.popoverPresentationController.sourceView = view; + [self presentViewController:actionSheet animated:YES completion:nil]; +} + - (void)declineRoomInvitation { // 'Decline' button has been pressed @@ -4977,16 +5015,15 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; else { [self startActivityIndicator]; - + MXWeakify(self); [self.roomDataSource.room leave:^{ + MXStrongifyAndReturnIfNil(self); [self stopActivityIndicator]; - - // We remove the current view controller. - // Pop to homes view controller - [[AppDelegate theDelegate] restoreInitialDisplay:^{}]; + [self popToHomeViewController]; } failure:^(NSError *error) { + MXStrongifyAndReturnIfNil(self); [self stopActivityIndicator]; MXLogDebug(@"[RoomVC] Failed to reject an invited room (%@) failed", self.roomDataSource.room.roomId); @@ -4995,6 +5032,31 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; } } +- (void)ignoreInviteSender +{ + [self startActivityIndicator]; + MXWeakify(self); + [self.roomDataSource.room ignoreInviteSender:^{ + MXStrongifyAndReturnIfNil(self); + + [self stopActivityIndicator]; + [self popToHomeViewController]; + + } failure:^(NSError *error) { + MXStrongifyAndReturnIfNil(self); + + [self stopActivityIndicator]; + MXLogDebug(@"[RoomVC] Failed to ignore inviter in room (%@)", self.roomDataSource.room.roomId); + }]; +} + +- (void)popToHomeViewController +{ + // We remove the current view controller. + // Pop to homes view controller + [[AppDelegate theDelegate] restoreInitialDisplay:^{}]; +} + #pragma mark - Typing management - (void)removeTypingNotificationsListener