From 17e252476f071054216c5563f053a30cc03f0e2e Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Tue, 20 Sep 2022 13:45:49 +0300 Subject: [PATCH 1/2] Release 1.9.6 (#6747) * Device manager: add user sessions overview current session strings. * Create UserSessionCardView to display session informations. * UserSessionsOverview: Handle current session section view. * Prepare for new sprint * Dismiss the launching screen when clearing cache. * Fix crash when previewing a room. * Fix typo in empty state * Code review fixes * Update swift-ogg and add changelog * Fix crash on logout from too much wrong pin codes * Update changelog to original issue * Disable unnecessary network breadcrumbs in Sentry * Changelog * Fix login crash on Xcode 14 builds Fixes #6722 * Put the session creator on the main actor instead. This covers all login and registration options. * Only disable the composer if the room is yet to be created. * Add missing source views for iPad. * New App Layout: fixed rooms list doesn't update after log out and log into another account * New layout: Fixed low priority rooms titles obscured by bottom bar when side scrolling * Fix replied event content parsing for nested replies * Fixed failed to join room (was not legal room) * Timeline composer layout loop fix (#6743) * Publish suitable view height for user suggestions * Update container view height * Add changelog * Fix user suggestions layout for pre iOS 16 * version++ Co-authored-by: SBiOSoftWhare Co-authored-by: Doug Co-authored-by: Germain Souquet Co-authored-by: Stefan Ceriu Co-authored-by: Aleksandrs Proskurins Co-authored-by: David Langley Co-authored-by: aringenbach Co-authored-by: aringenbach <80891108+aringenbach@users.noreply.github.com> Co-authored-by: Andy Uhnak Co-authored-by: Johannes Marbach Co-authored-by: Gil Eluard Co-authored-by: Gil Eluard Co-authored-by: gulekismail --- CHANGES.md | 22 +++ Config/AppVersion.xcconfig | 4 +- .../xcshareddata/swiftpm/Package.resolved | 2 +- Riot/Assets/en.lproj/Vector.strings | 10 +- Riot/Generated/Images.swift | 3 - Riot/Generated/Strings.swift | 26 ++- .../Analytics/SentryMonitoringClient.swift | 4 + Riot/Modules/Application/LegacyAppDelegate.m | 13 +- .../MatrixSDK/RecentsListService.swift | 8 + .../MXRoomAliasResolution+Deeplink.swift | 4 +- .../Home/AllChats/AllChatsCoordinator.swift | 7 +- .../AllChats/AllChatsViewController.swift | 34 +++- .../Utils/EventFormatter/MXKEventFormatter.m | 12 +- Riot/Modules/Room/RoomViewController.h | 1 + Riot/Modules/Room/RoomViewController.m | 18 +- Riot/Modules/Room/RoomViewController.xib | 3 +- .../Service/MatrixSDK/LoginWizard.swift | 12 +- .../MatrixSDK/RegistrationWizard.swift | 2 +- .../Service/MatrixSDK/SessionCreator.swift | 2 + .../UserSuggestionCoordinator.swift | 41 ++++- .../UserSuggestionCoordinatorBridge.swift | 5 + .../UserSessionCardView.swift | 166 ++++++++++++++++++ .../UserSessionCardViewData.swift | 80 +++++++++ .../UserSessionsOverviewModels.swift | 2 +- .../UserSessionsOverviewViewModel.swift | 8 +- .../View/UserSessionsOverview.swift | 29 ++- .../Mocks/MockSessionCreator.swift | 1 + .../MXRoomAliasResolutionDeeplinkTests.swift | 6 +- RiotTests/SessionCreatorTests.swift | 4 +- 29 files changed, 481 insertions(+), 48 deletions(-) create mode 100644 RiotSwiftUI/Modules/UserSessions/UserSessionCardView/UserSessionCardView.swift create mode 100644 RiotSwiftUI/Modules/UserSessions/UserSessionCardView/UserSessionCardViewData.swift diff --git a/CHANGES.md b/CHANGES.md index 6d0f6fef5..88c0155eb 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,25 @@ +## Changes in 1.9.6 (2022-09-20) + +🙌 Improvements + +- Sentry: Disable unnecessary network breadcrumbs ([#6726](https://github.com/vector-im/element-ios/pull/6726)) + +🐛 Bugfixes + +- Fix crash when some opus audio files are added to a room. ([#6584](https://github.com/vector-im/element-ios/issues/6584)) +- Fixed failed to join room (was not legal room) ([#6653](https://github.com/vector-im/element-ios/issues/6653)) +- Fix crash presenting Sign Out or Invite to Element menu items on iPad. ([#6654](https://github.com/vector-im/element-ios/issues/6654)) +- Fix crash on logout when syncing is currently in progress ([#6705](https://github.com/vector-im/element-ios/issues/6705)) +- New layout: Fixed Low priority rooms titles obscured by bottom bar when side scrolling ([#6707](https://github.com/vector-im/element-ios/issues/6707)) +- Message Composer: Stop the keyboard jumping after sending a message on certain devices. ([#6708](https://github.com/vector-im/element-ios/issues/6708)) +- New App Layout: Make sure the green loading spinner is dismissed after clearing the cache. ([#6709](https://github.com/vector-im/element-ios/issues/6709)) +- Fix a crash when previewing a room. ([#6712](https://github.com/vector-im/element-ios/issues/6712)) +- Fix login crash on Xcode 14 builds ([#6722](https://github.com/vector-im/element-ios/issues/6722)) +- Fix replied event content parsing for nested replies ([#6729](https://github.com/vector-im/element-ios/issues/6729)) +- Room: Fix a composer crash after long unsent messages. ([#6734](https://github.com/vector-im/element-ios/issues/6734)) +- New App Layout: fixed rooms list doesn't update after log out and log into another account ([#6739](https://github.com/vector-im/element-ios/issues/6739)) + + ## Changes in 1.9.5 (2022-09-12) 🐛 Bugfixes diff --git a/Config/AppVersion.xcconfig b/Config/AppVersion.xcconfig index fbe364eb0..160b9dc81 100644 --- a/Config/AppVersion.xcconfig +++ b/Config/AppVersion.xcconfig @@ -15,5 +15,5 @@ // // Version -MARKETING_VERSION = 1.9.5 -CURRENT_PROJECT_VERSION = 1.9.5 +MARKETING_VERSION = 1.9.6 +CURRENT_PROJECT_VERSION = 1.9.6 diff --git a/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved index a4ed2f4c0..3d248ff51 100644 --- a/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -42,7 +42,7 @@ "location" : "https://github.com/vector-im/swift-ogg", "state" : { "branch" : "main", - "revision" : "0ffad3f7b45a6a4760db090d503b00f094bbecc0" + "revision" : "e9a9e7601da662fd8b97d93781ff5c60b4becf88" } } ], diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index f346e5586..1a55df6d0 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -2187,7 +2187,7 @@ Tap the + to start adding people."; "all_chats_empty_space_information" = "Spaces are a new way to group rooms and people. Add an existing room, or create a new one, using the bottom-right button."; "all_chats_empty_view_information" = "The all-in-one secure chat app for teams, friends and organisations. Create a chat, or join an existing room, to get started."; "all_chats_empty_list_placeholder_title" = "You’re all caught up."; -"all_chats_empty_unreads_placeholder_message" = "This is where you're unread messages will show up, when you have some."; +"all_chats_empty_unreads_placeholder_message" = "This is where your unread messages will show up, when you have some."; "all_chats_nothing_found_placeholder_title" = "Nothing found."; "all_chats_nothing_found_placeholder_message" = "Try adjusting your search."; @@ -2361,11 +2361,19 @@ To enable access, tap Settings> Location and select Always"; "user_sessions_overview_other_sessions_section_title" = "OTHER SESSIONS"; "user_sessions_overview_other_sessions_section_info" = "For best security, verify your sessions and sign out from any session that you don’t recognize or use anymore."; +"user_sessions_overview_current_session_section_title" = "CURRENT SESSION"; + "user_session_verified" = "Verified session"; "user_session_unverified" = "Unverified session"; "user_session_verified_short" = "Verified"; "user_session_unverified_short" = "Unverified"; +"user_session_verify_action" = "Verify session"; +"user_session_view_details" = "View details"; +"user_session_learn_more" = "Learn more"; +"user_session_verified_additional_info" = "Your current session is ready for secure messaging."; +"user_session_unverified_additional_info" = "Verify your current session for enhanced secure messaging."; + // First item is client name and second item is session display name "user_session_name" = "%@: %@"; diff --git a/Riot/Generated/Images.swift b/Riot/Generated/Images.swift index 5b0b1d986..6fc13773b 100644 --- a/Riot/Generated/Images.swift +++ b/Riot/Generated/Images.swift @@ -115,8 +115,6 @@ internal class Asset: NSObject { internal static let encryptionWarning = ImageAsset(name: "encryption_warning") internal static let favouritesEmptyScreenArtwork = ImageAsset(name: "favourites_empty_screen_artwork") internal static let favouritesEmptyScreenArtworkDark = ImageAsset(name: "favourites_empty_screen_artwork_dark") - internal static let allChatRecents = ImageAsset(name: "all_chat_recents") - internal static let allChatUnreads = ImageAsset(name: "all_chat_unreads") internal static let roomActionDirectChat = ImageAsset(name: "room_action_direct_chat") internal static let roomActionFavourite = ImageAsset(name: "room_action_favourite") internal static let roomActionLeave = ImageAsset(name: "room_action_leave") @@ -124,7 +122,6 @@ internal class Asset: NSObject { internal static let roomActionNotificationMuted = ImageAsset(name: "room_action_notification_muted") internal static let roomActionPriorityHigh = ImageAsset(name: "room_action_priority_high") internal static let roomActionPriorityLow = ImageAsset(name: "room_action_priority_low") - internal static let allChatEditLayout = ImageAsset(name: "all_chat_edit_layout") internal static let allChatsEditIcon = ImageAsset(name: "all_chats_edit_icon") internal static let allChatsEmptyListPlaceholderIcon = ImageAsset(name: "all_chats_empty_list_placeholder_icon") internal static let allChatsEmptyScreenArtwork = ImageAsset(name: "all_chats_empty_screen_artwork") diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 42a3929a0..94a7f4631 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -187,7 +187,7 @@ public class VectorL10n: NSObject { public static var allChatsEmptySpaceInformation: String { return VectorL10n.tr("Vector", "all_chats_empty_space_information") } - /// This is where you're unread messages will show up, when you have some. + /// This is where your unread messages will show up, when you have some. public static var allChatsEmptyUnreadsPlaceholderMessage: String { return VectorL10n.tr("Vector", "all_chats_empty_unreads_placeholder_message") } @@ -8471,6 +8471,10 @@ public class VectorL10n: NSObject { public static func userSessionItemDetails(_ p1: String, _ p2: String) -> String { return VectorL10n.tr("Vector", "user_session_item_details", p1, p2) } + /// Learn more + public static var userSessionLearnMore: String { + return VectorL10n.tr("Vector", "user_session_learn_more") + } /// %@: %@ public static func userSessionName(_ p1: String, _ p2: String) -> String { return VectorL10n.tr("Vector", "user_session_name", p1, p2) @@ -8479,6 +8483,10 @@ public class VectorL10n: NSObject { public static var userSessionUnverified: String { return VectorL10n.tr("Vector", "user_session_unverified") } + /// Verify your current session for enhanced secure messaging. + public static var userSessionUnverifiedAdditionalInfo: String { + return VectorL10n.tr("Vector", "user_session_unverified_additional_info") + } /// Unverified public static var userSessionUnverifiedShort: String { return VectorL10n.tr("Vector", "user_session_unverified_short") @@ -8487,10 +8495,26 @@ public class VectorL10n: NSObject { public static var userSessionVerified: String { return VectorL10n.tr("Vector", "user_session_verified") } + /// Your current session is ready for secure messaging. + public static var userSessionVerifiedAdditionalInfo: String { + return VectorL10n.tr("Vector", "user_session_verified_additional_info") + } /// Verified public static var userSessionVerifiedShort: String { return VectorL10n.tr("Vector", "user_session_verified_short") } + /// Verify session + public static var userSessionVerifyAction: String { + return VectorL10n.tr("Vector", "user_session_verify_action") + } + /// View details + public static var userSessionViewDetails: String { + return VectorL10n.tr("Vector", "user_session_view_details") + } + /// CURRENT SESSION + public static var userSessionsOverviewCurrentSessionSectionTitle: String { + return VectorL10n.tr("Vector", "user_sessions_overview_current_session_section_title") + } /// For best security, verify your sessions and sign out from any session that you don’t recognize or use anymore. public static var userSessionsOverviewOtherSessionsSectionInfo: String { return VectorL10n.tr("Vector", "user_sessions_overview_other_sessions_section_info") diff --git a/Riot/Modules/Analytics/SentryMonitoringClient.swift b/Riot/Modules/Analytics/SentryMonitoringClient.swift index e296c0d5d..d15cf8039 100644 --- a/Riot/Modules/Analytics/SentryMonitoringClient.swift +++ b/Riot/Modules/Analytics/SentryMonitoringClient.swift @@ -37,6 +37,10 @@ struct SentryMonitoringClient { options.sampleRate = 0.1 options.tracesSampleRate = 0.1 + // Disable unnecessary network tracking + options.enableNetworkBreadcrumbs = false + options.enableNetworkTracking = false + options.beforeSend = { event in MXLog.debug("[SentryMonitoringClient] Issue detected: \(event)") return event diff --git a/Riot/Modules/Application/LegacyAppDelegate.m b/Riot/Modules/Application/LegacyAppDelegate.m index 865a01002..718669fa4 100644 --- a/Riot/Modules/Application/LegacyAppDelegate.m +++ b/Riot/Modules/Application/LegacyAppDelegate.m @@ -2162,6 +2162,9 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni - (void)logoutSendingRequestServer:(BOOL)sendLogoutServerRequest completion:(void (^)(BOOL isLoggedOut))completion { + MXSession *mainSession = self.mxSessions.firstObject; + [mainSession close]; + [self.pushNotificationService deregisterRemoteNotifications]; // Clear cache @@ -4360,8 +4363,14 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni { if (dueToTooManyErrors) { - [self showAlertWithTitle:nil message:[VectorL10n pinProtectionKickUserAlertMessage]]; - [self logoutWithConfirmation:NO completion:nil]; + [coordinatorBridgePresenter dismissWithMainAppWindow:self.window]; + self.setPinCoordinatorBridgePresenter = nil; + [self logoutWithConfirmation:NO completion:^(BOOL isLoggedOut) { + if (isLoggedOut) + { + [self showAlertWithTitle:nil message:[VectorL10n pinProtectionKickUserAlertMessage]]; + } + }]; } else { diff --git a/Riot/Modules/Common/Recents/Service/MatrixSDK/RecentsListService.swift b/Riot/Modules/Common/Recents/Service/MatrixSDK/RecentsListService.swift index 74effcd99..938361d00 100644 --- a/Riot/Modules/Common/Recents/Service/MatrixSDK/RecentsListService.swift +++ b/Riot/Modules/Common/Recents/Service/MatrixSDK/RecentsListService.swift @@ -638,6 +638,14 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol { guard let session = session else { return } + guard session.state != .closed else { + MXLog.debug("[RecentsListService] createFetchers cancelled on closed session") + return + } + guard session.roomListDataManager != nil else { + MXLog.debug("[RecentsListService] createFetchers cancelled on race condition (session closing in progress)") + return + } guard session.isEventStreamInitialised else { return } diff --git a/Riot/Modules/DeepLink/MXRoomAliasResolution+Deeplink.swift b/Riot/Modules/DeepLink/MXRoomAliasResolution+Deeplink.swift index 234f07849..ddded6927 100644 --- a/Riot/Modules/DeepLink/MXRoomAliasResolution+Deeplink.swift +++ b/Riot/Modules/DeepLink/MXRoomAliasResolution+Deeplink.swift @@ -29,9 +29,7 @@ import MatrixSDK return nil } - return MXTools.encodeURIComponent( - fragment(for: roomId) - ) + return fragment(for: roomId) } private func fragment(for roomId: String) -> String { diff --git a/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift b/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift index 410625b02..27af3a94b 100644 --- a/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift +++ b/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift @@ -344,7 +344,8 @@ class AllChatsCoordinator: NSObject, SplitViewMasterCoordinatorProtocol { var subMenuActions: [UIAction] = [] if BuildSettings.sideMenuShowInviteFriends { subMenuActions.append(UIAction(title: VectorL10n.sideMenuActionInviteFriends, image: UIImage(systemName: "square.and.arrow.up.fill")) { [weak self] action in - self?.showInviteFriends(from: nil) + guard let self = self else { return } + self.showInviteFriends(from: self.avatarMenuButton) }) } @@ -585,7 +586,7 @@ class AllChatsCoordinator: NSObject, SplitViewMasterCoordinatorProtocol { signOutAlertPresenter.present(for: keyBackup.state, areThereKeysToBackup: keyBackup.hasKeysToBackup, from: self.allChatsViewController, - sourceView: nil, + sourceView: avatarMenuButton, animated: true) } @@ -767,7 +768,7 @@ extension AllChatsCoordinator: AllChatsViewControllerDelegate { self.showRoom(withNavigationParameters: roomNavigationParameters, completion: completion) } - func allChatsViewController(_ allChatsViewController: AllChatsViewController, didSelectRoomPreviewWithParameters roomPreviewNavigationParameters: RoomPreviewNavigationParameters, completion: @escaping () -> Void) { + func allChatsViewController(_ allChatsViewController: AllChatsViewController, didSelectRoomPreviewWithParameters roomPreviewNavigationParameters: RoomPreviewNavigationParameters, completion: (() -> Void)?) { self.showRoomPreview(withNavigationParameters: roomPreviewNavigationParameters, completion: completion) } diff --git a/Riot/Modules/Home/AllChats/AllChatsViewController.swift b/Riot/Modules/Home/AllChats/AllChatsViewController.swift index 652426e32..d1feec95a 100644 --- a/Riot/Modules/Home/AllChats/AllChatsViewController.swift +++ b/Riot/Modules/Home/AllChats/AllChatsViewController.swift @@ -22,7 +22,7 @@ import Reusable protocol AllChatsViewControllerDelegate: AnyObject { func allChatsViewControllerDidCompleteAuthentication(_ allChatsViewController: AllChatsViewController) func allChatsViewController(_ allChatsViewController: AllChatsViewController, didSelectRoomWithParameters roomNavigationParameters: RoomNavigationParameters, completion: @escaping () -> Void) - func allChatsViewController(_ allChatsViewController: AllChatsViewController, didSelectRoomPreviewWithParameters roomPreviewNavigationParameters: RoomPreviewNavigationParameters, completion: @escaping () -> Void) + func allChatsViewController(_ allChatsViewController: AllChatsViewController, didSelectRoomPreviewWithParameters roomPreviewNavigationParameters: RoomPreviewNavigationParameters, completion: (() -> Void)?) func allChatsViewController(_ allChatsViewController: AllChatsViewController, didSelectContact contact: MXKContact, with presentationParameters: ScreenPresentationParameters) } @@ -208,7 +208,27 @@ class AllChatsViewController: HomeViewController { override func addMatrixSession(_ mxSession: MXSession!) { super.addMatrixSession(mxSession) - initDataSource() + + if let dataSource = dataSource, !dataSource.mxSessions.contains(where: { $0 as? MXSession == mxSession }) { + dataSource.addMatrixSession(mxSession) + // Setting the delegate is required to send a RecentsViewControllerDataReadyNotification. + // Without this, when clearing the cache we end up with an infinite green spinner. + (dataSource as? RecentsDataSource)?.setDelegate(self, andRecentsDataSourceMode: recentsDataSourceMode) + } else { + initDataSource() + } + } + + override func removeMatrixSession(_ mxSession: MXSession!) { + super.removeMatrixSession(mxSession) + + guard let dataSource = dataSource else { return } + dataSource.removeMatrixSession(mxSession) + + if dataSource.mxSessions.isEmpty { + // The user logged out -> we need to reset the data source + displayList(nil) + } } private func initDataSource() { @@ -336,12 +356,20 @@ class AllChatsViewController: HomeViewController { } override func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { + guard scrollView == recentsTableView else { + return + } + initialScrollPosition = scrollPosition(of: scrollView) } override func scrollViewDidScroll(_ scrollView: UIScrollView) { super.scrollViewDidScroll(scrollView) + guard scrollView == recentsTableView else { + return + } + let scrollPosition = scrollPosition(of: scrollView) if !self.recentsTableView.isDragging && scrollPosition == 0 && self.navigationController?.isToolbarHidden == true { @@ -854,7 +882,7 @@ extension AllChatsViewController: SplitViewMasterViewControllerProtocol { /// - Parameters: /// - parameters: the presentation parameters that contains room preview information plus display information. /// - completion: the block to execute at the end of the operation. - func selectRoomPreview(with parameters: RoomPreviewNavigationParameters, completion: @escaping () -> Void) { + func selectRoomPreview(with parameters: RoomPreviewNavigationParameters, completion: (() -> Void)?) { releaseSelectedItem() let roomPreviewData = parameters.previewData diff --git a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m index fa6495fd5..63f86617a 100644 --- a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m +++ b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m @@ -1846,7 +1846,17 @@ static NSString *const kHTMLATagRegexPattern = @"( } else { - MXJSONModelSetString(repliedEventContent, repliedEvent.content[@"formatted_body"]); + MXReplyEventParser *parser = [[MXReplyEventParser alloc] init]; + MXReplyEventParts *parts = [parser parse:repliedEvent]; + MXJSONModelSetString(repliedEventContent, parts.formattedBodyParts.replyText) + if (!repliedEventContent) + { + MXJSONModelSetString(repliedEventContent, parts.bodyParts.replyText) + } + if (!repliedEventContent) + { + MXJSONModelSetString(repliedEventContent, repliedEvent.content[@"formatted_body"]); + } if (!repliedEventContent) { MXJSONModelSetString(repliedEventContent, repliedEvent.content[kMXMessageBodyKey]); diff --git a/Riot/Modules/Room/RoomViewController.h b/Riot/Modules/Room/RoomViewController.h index 2b0ad02c5..a01f6c567 100644 --- a/Riot/Modules/Room/RoomViewController.h +++ b/Riot/Modules/Room/RoomViewController.h @@ -55,6 +55,7 @@ extern NSNotificationName const RoomGroupCallTileTappedNotification; // The preview header @property (weak, nonatomic, nullable) IBOutlet UIView *previewHeaderContainer; @property (weak, nonatomic, nullable) IBOutlet NSLayoutConstraint *previewHeaderContainerHeightConstraint; +@property (weak, nonatomic, nullable) IBOutlet NSLayoutConstraint *userSuggestionContainerHeightConstraint; // The jump to last unread banner @property (weak, nonatomic, nullable) IBOutlet UIView *jumpToLastUnreadBannerContainer; diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index 771c3d657..542007a41 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -1544,10 +1544,6 @@ static CGSize kThreadListBarButtonItemImageSize; */ - (void)createDiscussionIfNeeded:(void (^)(BOOL readyToSend))onComplete { - // Disable the input tool bar during this operation. This prevents us from creating several discussions, or - // trying to send several invites. - self.inputToolbarView.userInteractionEnabled = false; - void(^completion)(BOOL) = ^(BOOL readyToSend) { self.inputToolbarView.userInteractionEnabled = true; if (onComplete) { @@ -1557,6 +1553,10 @@ static CGSize kThreadListBarButtonItemImageSize; if (self.directChatTargetUser) { + // Disable the input tool bar during this operation. This prevents us from creating several discussions, or + // trying to send several invites. + self.inputToolbarView.userInteractionEnabled = false; + [self createDiscussionWithUser:self.directChatTargetUser completion:completion]; } else @@ -7757,6 +7757,16 @@ static CGSize kThreadListBarButtonItemImageSize; [self mention:member]; } +- (void)userSuggestionCoordinatorBridge:(UserSuggestionCoordinatorBridge *)coordinator didUpdateViewHeight:(CGFloat)height +{ + if (self.userSuggestionContainerHeightConstraint.constant != height) + { + self.userSuggestionContainerHeightConstraint.constant = height; + + [self.view layoutIfNeeded]; + } +} + #pragma mark - ThreadsCoordinatorBridgePresenterDelegate - (void)threadsCoordinatorBridgePresenterDelegateDidComplete:(ThreadsCoordinatorBridgePresenter *)coordinatorBridgePresenter diff --git a/Riot/Modules/Room/RoomViewController.xib b/Riot/Modules/Room/RoomViewController.xib index 888aa3b75..073276604 100644 --- a/Riot/Modules/Room/RoomViewController.xib +++ b/Riot/Modules/Room/RoomViewController.xib @@ -32,6 +32,7 @@ + @@ -171,7 +172,7 @@ - + diff --git a/RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/LoginWizard.swift b/RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/LoginWizard.swift index f56319f37..ae759b058 100644 --- a/RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/LoginWizard.swift +++ b/RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/LoginWizard.swift @@ -78,9 +78,9 @@ class LoginWizard { } let credentials = try await client.login(parameters: parameters) - return sessionCreator.createSession(credentials: credentials, - client: client, - removeOtherAccounts: removeOtherAccounts) + return await sessionCreator.createSession(credentials: credentials, + client: client, + removeOtherAccounts: removeOtherAccounts) } /// Exchange a login token to an access token. @@ -91,9 +91,9 @@ class LoginWizard { func login(with token: String, removeOtherAccounts: Bool = false) async throws -> MXSession { let parameters = LoginTokenParameters(token: token) let credentials = try await client.login(parameters: parameters) - return sessionCreator.createSession(credentials: credentials, - client: client, - removeOtherAccounts: removeOtherAccounts) + return await sessionCreator.createSession(credentials: credentials, + client: client, + removeOtherAccounts: removeOtherAccounts) } /// Ask the homeserver to reset the user password. The password will not be diff --git a/RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/RegistrationWizard.swift b/RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/RegistrationWizard.swift index 9f05a582b..2a2a0989b 100644 --- a/RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/RegistrationWizard.swift +++ b/RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/RegistrationWizard.swift @@ -255,7 +255,7 @@ class RegistrationWizard { do { let response = try await client.register(parameters: parameters) let credentials = MXCredentials(loginResponse: response, andDefaultCredentials: client.credentials) - return .success(sessionCreator.createSession(credentials: credentials, client: client, removeOtherAccounts: false)) + return await .success(sessionCreator.createSession(credentials: credentials, client: client, removeOtherAccounts: false)) } catch { let nsError = error as NSError diff --git a/RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/SessionCreator.swift b/RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/SessionCreator.swift index c51f2bb61..955f13fed 100644 --- a/RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/SessionCreator.swift +++ b/RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/SessionCreator.swift @@ -23,6 +23,7 @@ protocol SessionCreatorProtocol { /// - client: The client that completed the authentication. /// - removeOtherAccounts: Flag to remove other accounts than the account specified with the `credentials.userId`. /// - Returns: A new `MXSession` for the account. + @MainActor func createSession(credentials: MXCredentials, client: AuthenticationRestClient, removeOtherAccounts: Bool) -> MXSession } @@ -35,6 +36,7 @@ struct SessionCreator: SessionCreatorProtocol { self.accountManager = accountManager } + @MainActor func createSession(credentials: MXCredentials, client: AuthenticationRestClient, removeOtherAccounts: Bool) -> MXSession { // Use identity server provided in the client if credentials.identityServer == nil { diff --git a/RiotSwiftUI/Modules/Room/UserSuggestion/Coordinator/UserSuggestionCoordinator.swift b/RiotSwiftUI/Modules/Room/UserSuggestion/Coordinator/UserSuggestionCoordinator.swift index 4d10fce83..fd7bd57b3 100644 --- a/RiotSwiftUI/Modules/Room/UserSuggestion/Coordinator/UserSuggestionCoordinator.swift +++ b/RiotSwiftUI/Modules/Room/UserSuggestion/Coordinator/UserSuggestionCoordinator.swift @@ -17,9 +17,11 @@ import Foundation import UIKit import SwiftUI +import Combine protocol UserSuggestionCoordinatorDelegate: AnyObject { func userSuggestionCoordinator(_ coordinator: UserSuggestionCoordinator, didRequestMentionForMember member: MXRoomMember, textTrigger: String?) + func userSuggestionCoordinator(_ coordinator: UserSuggestionCoordinator, didUpdateViewHeight height: CGFloat) } struct UserSuggestionCoordinatorParameters { @@ -35,10 +37,12 @@ final class UserSuggestionCoordinator: Coordinator, Presentable { private let parameters: UserSuggestionCoordinatorParameters - private var userSuggestionHostingController: UIViewController + private var userSuggestionHostingController: UIHostingController private var userSuggestionService: UserSuggestionServiceProtocol private var userSuggestionViewModel: UserSuggestionViewModelProtocol private var roomMemberProvider: UserSuggestionCoordinatorRoomMemberProvider + + private var cancellables = Set() // MARK: Public @@ -77,12 +81,18 @@ final class UserSuggestionCoordinator: Coordinator, Presentable { self.delegate?.userSuggestionCoordinator(self, didRequestMentionForMember: member, textTrigger: self.userSuggestionService.currentTextTrigger) } } + + userSuggestionService.items.sink { [weak self] _ in + guard let self = self else { return } + self.delegate?.userSuggestionCoordinator(self, + didUpdateViewHeight: self.calculateViewHeight()) + }.store(in: &cancellables) } func processTextMessage(_ textMessage: String) { userSuggestionService.processTextMessage(textMessage) } - + // MARK: - Public func start() { @@ -91,6 +101,33 @@ final class UserSuggestionCoordinator: Coordinator, Presentable { func toPresentable() -> UIViewController { return self.userSuggestionHostingController } + + // MARK: - Private + + private func calculateViewHeight() -> CGFloat { + let viewModel = UserSuggestionViewModel(userSuggestionService: userSuggestionService) + let view = UserSuggestionList(viewModel: viewModel.context) + .addDependency(AvatarService.instantiate(mediaManager: parameters.mediaManager)) + + let controller = VectorHostingController(rootView: view) + guard let view = controller.view else { + return 0 + } + view.isHidden = true + + toPresentable().view.addSubview(view) + controller.didMove(toParent: toPresentable()) + + view.setNeedsLayout() + view.layoutIfNeeded() + + let result = view.intrinsicContentSize.height + + controller.didMove(toParent: nil) + view.removeFromSuperview() + + return result + } } private class UserSuggestionCoordinatorRoomMemberProvider: RoomMembersProviderProtocol { diff --git a/RiotSwiftUI/Modules/Room/UserSuggestion/Coordinator/UserSuggestionCoordinatorBridge.swift b/RiotSwiftUI/Modules/Room/UserSuggestion/Coordinator/UserSuggestionCoordinatorBridge.swift index 1fd88e25b..44ddaee9f 100644 --- a/RiotSwiftUI/Modules/Room/UserSuggestion/Coordinator/UserSuggestionCoordinatorBridge.swift +++ b/RiotSwiftUI/Modules/Room/UserSuggestion/Coordinator/UserSuggestionCoordinatorBridge.swift @@ -19,6 +19,7 @@ import Foundation @objc protocol UserSuggestionCoordinatorBridgeDelegate: AnyObject { func userSuggestionCoordinatorBridge(_ coordinator: UserSuggestionCoordinatorBridge, didRequestMentionForMember member: MXRoomMember, textTrigger: String?) + func userSuggestionCoordinatorBridge(_ coordinator: UserSuggestionCoordinatorBridge, didUpdateViewHeight height: CGFloat) } @objcMembers @@ -54,4 +55,8 @@ extension UserSuggestionCoordinatorBridge: UserSuggestionCoordinatorDelegate { func userSuggestionCoordinator(_ coordinator: UserSuggestionCoordinator, didRequestMentionForMember member: MXRoomMember, textTrigger: String?) { delegate?.userSuggestionCoordinatorBridge(self, didRequestMentionForMember: member, textTrigger: textTrigger) } + + func userSuggestionCoordinator(_ coordinator: UserSuggestionCoordinator, didUpdateViewHeight height: CGFloat) { + delegate?.userSuggestionCoordinatorBridge(self, didUpdateViewHeight: height) + } } diff --git a/RiotSwiftUI/Modules/UserSessions/UserSessionCardView/UserSessionCardView.swift b/RiotSwiftUI/Modules/UserSessions/UserSessionCardView/UserSessionCardView.swift new file mode 100644 index 000000000..7032d5701 --- /dev/null +++ b/RiotSwiftUI/Modules/UserSessions/UserSessionCardView/UserSessionCardView.swift @@ -0,0 +1,166 @@ +// +// Copyright 2022 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 SwiftUI +import DesignKit + +struct UserSessionCardView: View { + + @Environment(\.theme) var theme: ThemeSwiftUI + + var viewData: UserSessionCardViewData + + var onVerifyAction: ((String) -> (Void))? = nil + var onViewDetailsAction: ((String) -> (Void))? = nil + var onLearnMoreAction: (() -> (Void))? = nil + + private var verificationStatusImageName: String { + return viewData.isVerified ? Asset.Images.userSessionVerified.name : Asset.Images.userSessionUnverified.name + } + + private var verificationStatusText: String { + return viewData.isVerified ? VectorL10n.userSessionVerified : VectorL10n.userSessionUnverified + } + + private var verificationStatusColor: Color { + return viewData.isVerified ? theme.colors.accent : theme.colors.alert + } + + private var verificationStatusAdditionalInfoText: String { + return viewData.isVerified ? VectorL10n.userSessionVerifiedAdditionalInfo : VectorL10n.userSessionUnverifiedAdditionalInfo + } + + private var backgroundShape: RoundedRectangle { + return RoundedRectangle(cornerRadius: 8) + } + + private var showExtraInformations: Bool { + return viewData.isCurrentSessionDisplayMode == false && (viewData.lastActivityDateString.isEmptyOrNil == false || viewData.lastSeenIPInfo.isEmptyOrNil == false) + } + + var body: some View { + VStack(alignment: .center, spacing: 12) { + DeviceAvatarView(viewData: viewData.deviceAvatarViewData) + + Text(viewData.sessionName) + .font(theme.fonts.headline) + .foregroundColor(theme.colors.primaryContent) + .multilineTextAlignment(.center) + + HStack { + Image(verificationStatusImageName) + Text(verificationStatusText) + .font(theme.fonts.subheadline) + .foregroundColor(verificationStatusColor) + .multilineTextAlignment(.center) + } + + if viewData.isCurrentSessionDisplayMode { + Text(verificationStatusAdditionalInfoText) + .font(theme.fonts.footnote) + .foregroundColor(theme.colors.secondaryContent) + .multilineTextAlignment(.center) + } else { + InlineTextButton(verificationStatusAdditionalInfoText + " %@", tappableText: VectorL10n.userSessionLearnMore) { + onLearnMoreAction?() + } + .font(theme.fonts.footnote) + .foregroundColor(theme.colors.secondaryContent) + .multilineTextAlignment(.center) + } + + if self.showExtraInformations { + VStack(spacing: 2) { + if let lastActivityDateString = viewData.lastActivityDateString, lastActivityDateString.isEmpty == false { + Text(lastActivityDateString) + .font(theme.fonts.footnote) + .foregroundColor(theme.colors.secondaryContent) + .multilineTextAlignment(.center) + } + + if let lastSeenIPInfo = viewData.lastSeenIPInfo, lastSeenIPInfo.isEmpty == false { + Text(lastSeenIPInfo) + .font(theme.fonts.footnote) + .foregroundColor(theme.colors.secondaryContent) + .multilineTextAlignment(.center) + } + } + } + + if viewData.isVerified == false { + Button { + onVerifyAction?(viewData.sessionId) + } label: { + Text(VectorL10n.userSessionVerifyAction) + .font(theme.fonts.body) + } + .buttonStyle(PrimaryActionButtonStyle()) + .padding(.top, 4) + .padding(.bottom, 3) + } + + if viewData.isCurrentSessionDisplayMode { + Button { + onViewDetailsAction?(viewData.sessionId) + } label: { + Text(VectorL10n.userSessionViewDetails) + .font(theme.fonts.body) + .foregroundColor(theme.colors.accent) + } + .padding(.top, 4) + } + } + .padding(24) + .frame(maxWidth: .infinity) + .background(theme.colors.background) + .clipShape(self.backgroundShape) + .shapedBorder(color: theme.colors.quinaryContent, borderWidth: 1.0, shape: self.backgroundShape) + } +} + +struct UserSessionCardViewPreview: View { + + @Environment(\.theme) var theme: ThemeSwiftUI + + let viewData: UserSessionCardViewData + + init(isCurrentSessionInfo: Bool = false) { + let currentSessionInfo = UserSessionInfo(sessionId: "alice", sessionName: "iOS", deviceType: .mobile, isVerified: false, lastSeenIP: "10.0.0.10", lastSeenTimestamp: Date().timeIntervalSince1970 - 100) + + viewData = UserSessionCardViewData(userSessionInfo: currentSessionInfo, isCurrentSessionDisplayMode: isCurrentSessionInfo) + } + + var body: some View { + VStack { + UserSessionCardView(viewData: self.viewData) + } + .frame(maxWidth: .infinity) + .background(theme.colors.system) + .padding() + } +} + +struct UserSessionCardView_Previews: PreviewProvider { + + static var previews: some View { + Group { + UserSessionCardViewPreview(isCurrentSessionInfo: true).theme(.light).preferredColorScheme(.light) + UserSessionCardViewPreview(isCurrentSessionInfo: true).theme(.dark).preferredColorScheme(.dark) + UserSessionCardViewPreview().theme(.light).preferredColorScheme(.light) + UserSessionCardViewPreview().theme(.dark).preferredColorScheme(.dark) + } + } +} diff --git a/RiotSwiftUI/Modules/UserSessions/UserSessionCardView/UserSessionCardViewData.swift b/RiotSwiftUI/Modules/UserSessions/UserSessionCardView/UserSessionCardViewData.swift new file mode 100644 index 000000000..d63175a0e --- /dev/null +++ b/RiotSwiftUI/Modules/UserSessions/UserSessionCardView/UserSessionCardViewData.swift @@ -0,0 +1,80 @@ +// +// Copyright 2022 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 + +/// View data for UserSessionCardView +struct UserSessionCardViewData { + + // MARK: - Constants + + private static let userSessionNameFormatter = UserSessionNameFormatter() + private static let lastActivityDateFormatter = UserSessionLastActivityFormatter() + + // MARK: - Properties + + var id: String { + return sessionId + } + + let sessionId: String + + let sessionName: String + + let isVerified: Bool + + let lastActivityDateString: String? + + let lastSeenIPInfo: String? + + let deviceAvatarViewData: DeviceAvatarViewData + + /// Indicate if the current user session is shown and to adpat the layout + let isCurrentSessionDisplayMode: Bool + + // MARK: - Setup + + init(sessionId: String, + sessionDisplayName: String?, + deviceType: DeviceType, + isVerified: Bool, + lastActivityTimestamp: TimeInterval?, + lastSeenIP: String?, + isCurrentSessionDisplayMode: Bool = false) { + self.sessionId = sessionId + self.sessionName = Self.userSessionNameFormatter.sessionName(deviceType: deviceType, sessionDisplayName: sessionDisplayName) + self.isVerified = isVerified + + var lastActivityDateString: String? + + if let lastActivityTimestamp = lastActivityTimestamp { + lastActivityDateString = Self.lastActivityDateFormatter.lastActivityDateString(from: lastActivityTimestamp) + } + + self.lastActivityDateString = lastActivityDateString + self.lastSeenIPInfo = lastSeenIP + self.deviceAvatarViewData = DeviceAvatarViewData(deviceType: deviceType, isVerified: nil) + + self.isCurrentSessionDisplayMode = isCurrentSessionDisplayMode + } +} + +extension UserSessionCardViewData { + + init(userSessionInfo: UserSessionInfo, isCurrentSessionDisplayMode: Bool = false) { + self.init(sessionId: userSessionInfo.sessionId, sessionDisplayName: userSessionInfo.sessionName, deviceType: userSessionInfo.deviceType, isVerified: userSessionInfo.isVerified, lastActivityTimestamp: userSessionInfo.lastSeenTimestamp, lastSeenIP: userSessionInfo.lastSeenIP, isCurrentSessionDisplayMode: isCurrentSessionDisplayMode) + } +} diff --git a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/UserSessionsOverviewModels.swift b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/UserSessionsOverviewModels.swift index 5d01772fa..b5b408081 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/UserSessionsOverviewModels.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/UserSessionsOverviewModels.swift @@ -38,7 +38,7 @@ struct UserSessionsOverviewViewState: BindableState { var inactiveSessionsViewData: [UserSessionListItemViewData] - var currentSessionViewData: UserSessionListItemViewData? + var currentSessionViewData: UserSessionCardViewData? var otherSessionsViewData: [UserSessionListItemViewData] diff --git a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/UserSessionsOverviewViewModel.swift b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/UserSessionsOverviewViewModel.swift index 0edaf96bb..fcc5d73f4 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/UserSessionsOverviewViewModel.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/UserSessionsOverviewViewModel.swift @@ -37,9 +37,9 @@ class UserSessionsOverviewViewModel: UserSessionsOverviewViewModelType, UserSess init(userSessionsOverviewService: UserSessionsOverviewServiceProtocol) { self.userSessionsOverviewService = userSessionsOverviewService - let viewState = UserSessionsOverviewViewState(unverifiedSessionsViewData: [], inactiveSessionsViewData: [], currentSessionViewData: nil, otherSessionsViewData: []) + let initialViewState = UserSessionsOverviewViewState(unverifiedSessionsViewData: [], inactiveSessionsViewData: [], currentSessionViewData: nil, otherSessionsViewData: []) - super.init(initialViewState: viewState) + super.init(initialViewState: initialViewState) self.updateViewState(with: userSessionsOverviewService.lastOverviewData) } @@ -72,13 +72,13 @@ class UserSessionsOverviewViewModel: UserSessionsOverviewViewModelType, UserSess let unverifiedSessionsViewData = self.userSessionListItemViewDataList(from: userSessionsViewData.unverifiedSessionsInfo) let inactiveSessionsViewData = self.userSessionListItemViewDataList(from: userSessionsViewData.inactiveSessionsInfo) - var currentSessionViewData: UserSessionListItemViewData? + var currentSessionViewData: UserSessionCardViewData? let otherSessionsViewData = self.userSessionListItemViewDataList(from: userSessionsViewData.otherSessionsInfo) if let currentSessionInfo = userSessionsViewData.currentSessionInfo { - currentSessionViewData = UserSessionListItemViewData(userSessionInfo: currentSessionInfo) + currentSessionViewData = UserSessionCardViewData(userSessionInfo: currentSessionInfo, isCurrentSessionDisplayMode: true) } self.state.unverifiedSessionsViewData = unverifiedSessionsViewData diff --git a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/View/UserSessionsOverview.swift b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/View/UserSessionsOverview.swift index f4b49c4ea..fbfb70c3f 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/View/UserSessionsOverview.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/View/UserSessionsOverview.swift @@ -24,6 +24,28 @@ struct UserSessionsOverview: View { @Environment(\.theme) private var theme: ThemeSwiftUI + @ViewBuilder + private var currentSessionsSection: some View { + if let currentSessionViewData = viewModel.viewState.currentSessionViewData { + SwiftUI.Section { + UserSessionCardView(viewData: currentSessionViewData, onVerifyAction: { _ in + viewModel.send(viewAction: .verifyCurrentSession) + }, onViewDetailsAction: { _ in + viewModel.send(viewAction: .viewCurrentSessionDetails) + }) + .padding(.horizontal, 16) + } header: { + Text(VectorL10n.userSessionsOverviewCurrentSessionSectionTitle) + .font(theme.fonts.footnote) + .foregroundColor(theme.colors.secondaryContent) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.horizontal, 16) + .padding(.top, 24) + .padding(.bottom, 11) + } + } + } + // MARK: Public @ObservedObject var viewModel: UserSessionsOverviewViewModel.Context @@ -38,9 +60,7 @@ struct UserSessionsOverview: View { } // Current session section - if let currentSessionViewData = viewModel.viewState.currentSessionViewData { - // TODO: - } + currentSessionsSection // Other sessions section if viewModel.viewState.otherSessionsViewData.isEmpty == false { @@ -56,7 +76,7 @@ struct UserSessionsOverview: View { } } - var otherSessionsSection: some View { + private var otherSessionsSection: some View { SwiftUI.Section { // Device list @@ -81,6 +101,7 @@ struct UserSessionsOverview: View { .padding(.bottom, 11) } .padding(.horizontal, 16) + .padding(.top, 24) } } } diff --git a/RiotTests/Modules/Authentication/Mocks/MockSessionCreator.swift b/RiotTests/Modules/Authentication/Mocks/MockSessionCreator.swift index e62578d37..2b018dae2 100644 --- a/RiotTests/Modules/Authentication/Mocks/MockSessionCreator.swift +++ b/RiotTests/Modules/Authentication/Mocks/MockSessionCreator.swift @@ -20,6 +20,7 @@ import Foundation struct MockSessionCreator: SessionCreatorProtocol { /// Returns a basic session created from the supplied credentials. This prevents the app from setting up the account during tests. + @MainActor func createSession(credentials: MXCredentials, client: AuthenticationRestClient, removeOtherAccounts: Bool) -> MXSession { let client = MXRestClient(credentials: credentials, unauthenticatedHandler: { _,_,_,_ in }) // The handler is expected if credentials are set. diff --git a/RiotTests/Modules/DeepLink/MXRoomAliasResolutionDeeplinkTests.swift b/RiotTests/Modules/DeepLink/MXRoomAliasResolutionDeeplinkTests.swift index 27116d070..03120ecbb 100644 --- a/RiotTests/Modules/DeepLink/MXRoomAliasResolutionDeeplinkTests.swift +++ b/RiotTests/Modules/DeepLink/MXRoomAliasResolutionDeeplinkTests.swift @@ -28,7 +28,7 @@ class MXRoomAliasResolutionDeeplinkTests: XCTestCase { let resolution = MXRoomAliasResolution() resolution.roomId = "!abc:matrix.org" - XCTAssertEqual(resolution.deeplinkFragment, "!abc%3Amatrix.org") + XCTAssertEqual(resolution.deeplinkFragment, "!abc:matrix.org") } func test_fragmentContainsSingleServer() { @@ -38,7 +38,7 @@ class MXRoomAliasResolutionDeeplinkTests: XCTestCase { "matrix.org" ] - XCTAssertEqual(resolution.deeplinkFragment, "xyz%3Aelement.io%3Fvia%3Dmatrix.org") + XCTAssertEqual(resolution.deeplinkFragment, "xyz:element.io?via=matrix.org") } func test_fragmentContainsMultipleSerivers() { @@ -51,6 +51,6 @@ class MXRoomAliasResolutionDeeplinkTests: XCTestCase { "matrix.org" ] - XCTAssertEqual(resolution.deeplinkFragment, "mno%3Aserver.com%3Fvia%3Dserver.com%26via%3Delement.io%26via%3Dwikipedia.org%26via%3Dmatrix.org") + XCTAssertEqual(resolution.deeplinkFragment, "mno:server.com?via=server.com&via=element.io&via=wikipedia.org&via=matrix.org") } } diff --git a/RiotTests/SessionCreatorTests.swift b/RiotTests/SessionCreatorTests.swift index f2003545e..dbc28c728 100644 --- a/RiotTests/SessionCreatorTests.swift +++ b/RiotTests/SessionCreatorTests.swift @@ -19,7 +19,7 @@ import XCTest class SessionCreatorTests: XCTestCase { - func testIdentityServer() throws { + func testIdentityServer() async throws { let sessionCreator = SessionCreator(withAccountManager: .mock) let mockIS = "mock_identity_server" @@ -29,7 +29,7 @@ class SessionCreatorTests: XCTestCase { accessToken: "mock_access_token") let client = MXRestClient(credentials: credentials) client.identityServer = mockIS - let session = sessionCreator.createSession(credentials: credentials, client: client, removeOtherAccounts: false) + let session = await sessionCreator.createSession(credentials: credentials, client: client, removeOtherAccounts: false) XCTAssertEqual(credentials.identityServer, mockIS) XCTAssertEqual(session.credentials.identityServer, mockIS) From 11743f02b72cfb1620c5f1d0a375a07eb6531655 Mon Sep 17 00:00:00 2001 From: gulekismail Date: Tue, 20 Sep 2022 13:46:37 +0300 Subject: [PATCH 2/2] finish version++