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/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/Podfile.lock b/Podfile.lock index 06d7a51e9..1c3e87179 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -56,16 +56,16 @@ PODS: - LoggerAPI (1.9.200): - Logging (~> 1.1) - Logging (1.4.0) - - MatrixSDK (0.22.5): - - MatrixSDK/Core (= 0.22.5) - - MatrixSDK/Core (0.22.5): + - MatrixSDK (0.22.6): + - MatrixSDK/Core (= 0.22.6) + - MatrixSDK/Core (0.22.6): - AFNetworking (~> 4.0.0) - GZIP (~> 1.3.0) - libbase58 (~> 0.1.4) - OLMKit (~> 3.2.5) - Realm (= 10.16.0) - SwiftyBeaver (= 1.9.5) - - MatrixSDK/JingleCallStack (0.22.5): + - MatrixSDK/JingleCallStack (0.22.6): - JitsiMeetSDK (= 3.10.2) - MatrixSDK/Core - OLMKit (3.2.5): @@ -115,8 +115,8 @@ DEPENDENCIES: - KeychainAccess (~> 4.2.2) - KTCenterFlowLayout (~> 1.3.1) - libPhoneNumber-iOS (~> 0.9.13) - - MatrixSDK (= 0.22.5) - - MatrixSDK/JingleCallStack (= 0.22.5) + - MatrixSDK (= 0.22.6) + - MatrixSDK/JingleCallStack (= 0.22.6) - OLMKit - PostHog (~> 1.4.4) - ReadMoreTextView (~> 3.0.1) @@ -208,7 +208,7 @@ SPEC CHECKSUMS: libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75 LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d Logging: beeb016c9c80cf77042d62e83495816847ef108b - MatrixSDK: 9bbe59564b2352e54254119dd217a9d86e3f8b17 + MatrixSDK: f61997c146a03dfbf2ec0442bcae362c50666284 OLMKit: 9fb4799c4a044dd2c06bda31ec31a12191ad30b5 PostHog: 4b6321b521569092d4ef3a02238d9435dbaeb99f ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d @@ -225,6 +225,6 @@ SPEC CHECKSUMS: zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: 4e66f96dc80b17bfb36906bf85f9be35071cdbee +PODFILE CHECKSUM: 16aaf5e59ec902619fbfd799939f044728a92ab7 COCOAPODS: 1.11.2 diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index fb675d28e..af5aa32be 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -506,6 +506,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"; @@ -2168,6 +2169,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 f2ff7c539..ca1a6125a 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -2163,6 +2163,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") @@ -5467,6 +5471,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 042c0becc..9d3518a80 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]; @@ -2419,16 +2424,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]; } @@ -2436,7 +2441,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 6efc99584..c962e56d6 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -568,7 +568,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 @@ -938,10 +940,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]; @@ -950,6 +956,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) @@ -959,14 +967,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 @@ -4964,10 +4980,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 @@ -4978,16 +5016,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); @@ -4996,6 +5033,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