diff --git a/Riot/Modules/Analytics/Analytics.swift b/Riot/Modules/Analytics/Analytics.swift index c6296b28d..f72447201 100644 --- a/Riot/Modules/Analytics/Analytics.swift +++ b/Riot/Modules/Analytics/Analytics.swift @@ -45,6 +45,8 @@ import AnalyticsEvents /// The service used to interact with account data settings. private var service: AnalyticsService? + private var viewRoomActiveSpace: AnalyticsViewRoomActiveSpace = .home + /// Whether or not the object is enabled and sending events to the server. var isRunning: Bool { client.isRunning } @@ -59,6 +61,24 @@ import AnalyticsEvents RiotSettings.shared.hasAcceptedMatomoAnalytics } + var joinedRoomTrigger: AnalyticsJoinedRoomTrigger = .unknown + + var viewRoomTrigger: AnalyticsViewRoomTrigger = .unknown + + var activeSpace: MXSpace? { + didSet { + MXLog.debug("[Analytics] activeSpace space \(activeSpace?.summary?.displayname ?? "home")") + updateViewRoomActiveSpace() + } + } + + var exploringSpace: MXSpace? { + didSet { + MXLog.debug("[Analytics] exploring space \(exploringSpace?.summary?.displayname ?? "none")") + updateViewRoomActiveSpace() + } + } + // MARK: - Public /// Opts in to analytics tracking with the supplied session. @@ -165,6 +185,19 @@ import AnalyticsEvents private func capture(event: AnalyticsEventProtocol) { client.capture(event) } + + /// Update `viewRoomActiveSpace` property according to the current value of `exploringSpace` and `activeSpace` properties. + private func updateViewRoomActiveSpace() { + let space = exploringSpace ?? activeSpace + guard let spaceRoom = space?.room else { + viewRoomActiveSpace = .home + return + } + + spaceRoom.state { roomState in + self.viewRoomActiveSpace = roomState?.isJoinRulePublic == true ? .public : .private + } + } } // MARK: - Public tracking methods @@ -242,6 +275,28 @@ extension Analytics { func trackIdentityServerAccepted(_ accepted: Bool) { // Do we still want to track this? } + + /// Track view room event triggered when the user changes rooms. + /// - Parameters: + /// - room: the room being viewed + func trackViewRoom(_ room: MXRoom) { + trackViewRoom(asDM: room.isDirect, isSpace: room.summary?.roomType == .space) + } + + /// Track view room event triggered when the user changes rooms. + /// - Parameters: + /// - isDM: Whether the room is a DM. + /// - isSpace: Whether the room is a Space. + func trackViewRoom(asDM isDM: Bool, isSpace: Bool) { + MXLog.debug("[Analytics] trackViewRoom (asDM:\(isDM), isSpace:\(isSpace), trigger:\(viewRoomTrigger.trigger?.rawValue ?? "unknown"), activeSpace:\(viewRoomActiveSpace.space?.rawValue ?? "unknown"))") + let event = AnalyticsEvent.ViewRoom(activeSpace: viewRoomActiveSpace.space, + isDM: isDM, + isSpace: isSpace, + trigger: viewRoomTrigger.trigger, + viaKeyboard: nil) + viewRoomTrigger = .unknown + capture(event: event) + } } // MARK: - MXAnalyticsDelegate @@ -284,8 +339,10 @@ extension Analytics: MXAnalyticsDelegate { return } - let event = AnalyticsEvent.JoinedRoom(isDM: isDM, isSpace: isSpace, roomSize: roomSize, trigger: nil) + let event = AnalyticsEvent.JoinedRoom(isDM: isDM, isSpace: isSpace, roomSize: roomSize, trigger: joinedRoomTrigger.trigger) capture(event: event) + + self.joinedRoomTrigger = .unknown } /// **Note** This method isn't currently implemented. diff --git a/Riot/Modules/Analytics/AnalyticsJoinedRoomTrigger.swift b/Riot/Modules/Analytics/AnalyticsJoinedRoomTrigger.swift new file mode 100644 index 000000000..2b830870c --- /dev/null +++ b/Riot/Modules/Analytics/AnalyticsJoinedRoomTrigger.swift @@ -0,0 +1,50 @@ +// +// 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 +import AnalyticsEvents + +@objc enum AnalyticsJoinedRoomTrigger: Int { + case unknown + case invite + case notification + case roomDirectory + case roomPreview + case slashCommand + case spaceHierarchy + case timeline + + var trigger: AnalyticsEvent.JoinedRoom.Trigger? { + switch self { + case .unknown: + return nil + case .invite: + return .Invite + case .notification: + return .Notification + case .roomDirectory: + return .RoomDirectory + case .roomPreview: + return .RoomPreview + case .slashCommand: + return .SlashCommand + case .spaceHierarchy: + return .SpaceHierarchy + case .timeline: + return .Timeline + } + } +} diff --git a/Riot/Modules/Analytics/AnalyticsViewRoomActiveSpace.swift b/Riot/Modules/Analytics/AnalyticsViewRoomActiveSpace.swift new file mode 100644 index 000000000..20f541a15 --- /dev/null +++ b/Riot/Modules/Analytics/AnalyticsViewRoomActiveSpace.swift @@ -0,0 +1,41 @@ +// +// 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 +import AnalyticsEvents + +@objc enum AnalyticsViewRoomActiveSpace: Int { + case unknown + case home + case meta + case `private` + case `public` + + var space: AnalyticsEvent.ViewRoom.ActiveSpace? { + switch self { + case .unknown: + return nil + case .home: + return .Home + case .meta: + return .Meta + case .private: + return .Private + case .public: + return .Public + } + } +} diff --git a/Riot/Modules/Analytics/AnalyticsViewRoomTrigger.swift b/Riot/Modules/Analytics/AnalyticsViewRoomTrigger.swift new file mode 100644 index 000000000..1be27326a --- /dev/null +++ b/Riot/Modules/Analytics/AnalyticsViewRoomTrigger.swift @@ -0,0 +1,89 @@ +// +// 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 +import AnalyticsEvents + +@objc enum AnalyticsViewRoomTrigger: Int { + case unknown + case created + case messageSearch + case messageUser + case notification + case predecessor + case roomDirectory + case roomList + case spaceHierarchy + case timeline + case tombstone + case verificationRequest + case widget + case roomMemberDetail + case fileSearch + case roomSearch + case searchContactDetail + case spaceMemberDetail + case inCall + case spaceMenu + case spaceSettings + + var trigger: AnalyticsEvent.ViewRoom.Trigger? { + switch self { + case .unknown: + return nil + case .created: + return .Created + case .messageSearch: + return .MessageSearch + case .messageUser: + return .MessageUser + case .notification: + return .Notification + case .predecessor: + return .Predecessor + case .roomDirectory: + return .RoomDirectory + case .roomList: + return .RoomList + case .spaceHierarchy: + return .SpaceHierarchy + case .timeline: + return .Timeline + case .tombstone: + return .Tombstone + case .verificationRequest: + return .VerificationRequest + case .widget: + return .Widget + case .fileSearch: + return .MobileFileSearch + case .roomSearch: + return .MobileRoomSearch + case .roomMemberDetail: + return .MobileRoomMemberDetail + case .searchContactDetail: + return .MobileSearchContactDetail + case .spaceMemberDetail: + return .MobileSpaceMemberDetail + case .inCall: + return .MobileInCall + case .spaceMenu: + return .MobileSpaceMenu + case .spaceSettings: + return .MobileSpaceSettings + } + } +} diff --git a/Riot/Modules/Application/AppCoordinator.swift b/Riot/Modules/Application/AppCoordinator.swift index 3413a90ad..fef10f5b8 100755 --- a/Riot/Modules/Application/AppCoordinator.swift +++ b/Riot/Modules/Application/AppCoordinator.swift @@ -213,9 +213,11 @@ final class AppCoordinator: NSObject, AppCoordinatorType { case .homeSpace: MXLog.verbose("Switch to home space") self.navigateToSpace(with: nil) + Analytics.shared.activeSpace = nil case .space(let spaceId): MXLog.verbose("Switch to space with id: \(spaceId)") self.navigateToSpace(with: spaceId) + Analytics.shared.activeSpace = userSessionsService.mainUserSession?.matrixSession.spaceService.getSpace(withId: spaceId) } } diff --git a/Riot/Modules/Application/LegacyAppDelegate.m b/Riot/Modules/Application/LegacyAppDelegate.m index e177e2a4a..f7c2dff3b 100644 --- a/Riot/Modules/Application/LegacyAppDelegate.m +++ b/Riot/Modules/Application/LegacyAppDelegate.m @@ -1104,6 +1104,19 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni shouldNavigateToRoomWithId:(NSString *)roomId threadId:(NSString *)threadId { + if (roomId) + { + MXRoom *room = [self.mxSessions.firstObject roomWithRoomId:roomId]; + if (room.summary.membership != MXMembershipJoin) + { + Analytics.shared.joinedRoomTrigger = AnalyticsJoinedRoomTriggerNotification; + } + else + { + Analytics.shared.viewRoomTrigger = AnalyticsViewRoomTriggerNotification; + } + } + _lastNavigatedRoomIdFromPush = roomId; [self navigateToRoomById:roomId threadId:threadId]; } @@ -2941,6 +2954,11 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni { MXRoom *room = [mxSession roomWithRoomId:roomId]; + if (room && room.summary.membership == MXMembershipJoin) + { + [Analytics.shared trackViewRoom:room]; + } + // Indicates that spaces are not supported if (room.summary.roomType == MXRoomTypeSpace) { @@ -3172,6 +3190,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni [mxSession createRoomWithParameters:roomCreationParameters success:^(MXRoom *room) { // Open created room + Analytics.shared.viewRoomTrigger = AnalyticsViewRoomTriggerCreated; [self showRoom:room.roomId andEventId:nil withMatrixSession:mxSession]; if (completion) @@ -3206,6 +3225,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni if (directRoom) { // open it + Analytics.shared.viewRoomTrigger = AnalyticsViewRoomTriggerCreated; [self showRoom:directRoom.roomId andEventId:nil withMatrixSession:mxSession]; if (completion) diff --git a/Riot/Modules/Call/CallViewController.m b/Riot/Modules/Call/CallViewController.m index 8703e18c7..71c52ba72 100644 --- a/Riot/Modules/Call/CallViewController.m +++ b/Riot/Modules/Call/CallViewController.m @@ -563,6 +563,7 @@ CallAudioRouteMenuViewDelegate> if (self.mxCall.room) { // Open the room page + Analytics.shared.viewRoomTrigger = AnalyticsViewRoomTriggerInCall; [[AppDelegate theDelegate] showRoom:self.mxCall.room.roomId andEventId:nil withMatrixSession:self.mxCall.room.mxSession]; } diff --git a/Riot/Modules/Common/Recents/RecentsViewController.m b/Riot/Modules/Common/Recents/RecentsViewController.m index 042c0becc..d333a2e6c 100644 --- a/Riot/Modules/Common/Recents/RecentsViewController.m +++ b/Riot/Modules/Common/Recents/RecentsViewController.m @@ -873,6 +873,12 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro - (void)showRoomWithRoomId:(NSString*)roomId inMatrixSession:(MXSession*)matrixSession { + MXRoom *room = [matrixSession roomWithRoomId:roomId]; + if (room.summary.membership == MXMembershipInvite) + { + Analytics.shared.joinedRoomTrigger = AnalyticsJoinedRoomTriggerInvite; + } + // Avoid multiple openings of rooms self.userInteractionEnabled = NO; @@ -892,6 +898,8 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro - (void)showRoomPreviewWithData:(RoomPreviewData*)roomPreviewData { + Analytics.shared.joinedRoomTrigger = AnalyticsJoinedRoomTriggerRoomDirectory; + // Do not stack views when showing room ScreenPresentationParameters *presentationParameters = [[ScreenPresentationParameters alloc] initWithRestoreInitialDisplay:NO stackAboveVisibleViews:NO sender:nil sourceView:nil]; @@ -988,6 +996,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro } // Accept invitation + Analytics.shared.joinedRoomTrigger = AnalyticsJoinedRoomTriggerInvite; [self joinRoom:invitedRoom completion:nil]; } else if ([actionIdentifier isEqualToString:kInviteRecentTableViewCellDeclineButtonPressed]) @@ -2055,6 +2064,8 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro // Check whether the user has already joined the selected public room if ([self.recentsDataSource.publicRoomsDirectoryDataSource.mxSession isJoinedOnRoom:publicRoom.roomId]) { + Analytics.shared.viewRoomTrigger = AnalyticsViewRoomTriggerRoomDirectory; + // Open the public room [self showRoomWithRoomId:publicRoom.roomId inMatrixSession:self.recentsDataSource.publicRoomsDirectoryDataSource.mxSession]; @@ -2150,11 +2161,14 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro - (void)recentListViewController:(MXKRecentListViewController *)recentListViewController didSelectRoom:(NSString *)roomId inMatrixSession:(MXSession *)matrixSession { + Analytics.shared.viewRoomTrigger = AnalyticsViewRoomTriggerRoomList; [self showRoomWithRoomId:roomId inMatrixSession:matrixSession]; } - (void)recentListViewController:(MXKRecentListViewController *)recentListViewController didSelectSuggestedRoom:(MXSpaceChildInfo *)childInfo { + Analytics.shared.joinedRoomTrigger = AnalyticsJoinedRoomTriggerSpaceHierarchy; + RoomPreviewData *previewData = [[RoomPreviewData alloc] initWithSpaceChildInfo:childInfo andSession:self.mainSession]; [self startActivityIndicator]; MXWeakify(self); @@ -2214,6 +2228,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro - (void)createRoomCoordinatorBridgePresenterDelegate:(CreateRoomCoordinatorBridgePresenter *)coordinatorBridgePresenter didCreateNewRoom:(MXRoom *)room { [coordinatorBridgePresenter dismissWithAnimated:YES completion:^{ + Analytics.shared.viewRoomTrigger = AnalyticsViewRoomTriggerCreated; [self showRoomWithRoomId:room.roomId inMatrixSession:self.mainSession]; }]; coordinatorBridgePresenter = nil; diff --git a/Riot/Modules/Contacts/Details/ContactDetailsViewController.m b/Riot/Modules/Contacts/Details/ContactDetailsViewController.m index bc1815a41..76b161caf 100644 --- a/Riot/Modules/Contacts/Details/ContactDetailsViewController.m +++ b/Riot/Modules/Contacts/Details/ContactDetailsViewController.m @@ -801,6 +801,7 @@ if (indexPath.row < directChatsArray.count) { // Open this room + Analytics.shared.viewRoomTrigger = AnalyticsViewRoomTriggerSearchContactDetail; [[AppDelegate theDelegate] showRoom:directChatsArray[indexPath.row] andEventId:nil withMatrixSession:self.mainSession]; } else @@ -1053,7 +1054,8 @@ self->roomCreationRequest = nil; [self removePendingActionMask]; - + + Analytics.shared.viewRoomTrigger = AnalyticsViewRoomTriggerCreated; [[AppDelegate theDelegate] showRoom:room.roomId andEventId:nil withMatrixSession:self.mainSession]; } failure:onFailure]; diff --git a/Riot/Modules/CreateRoom/CreateRoomCoordinator.swift b/Riot/Modules/CreateRoom/CreateRoomCoordinator.swift index 8bc2f96d5..b86728e93 100644 --- a/Riot/Modules/CreateRoom/CreateRoomCoordinator.swift +++ b/Riot/Modules/CreateRoom/CreateRoomCoordinator.swift @@ -96,6 +96,7 @@ final class CreateRoomCoordinator: CreateRoomCoordinatorType { TabbedRouterTab(title: VectorL10n.existing, icon: nil, module: roomSelectionCoordinator) ] self.navigationRouter.setRootModule(self.tabRouter) + Analytics.shared.exploringSpace = parentSpace } else { self.navigationRouter.setRootModule(createRoomCoordinator) } diff --git a/Riot/Modules/GlobalSearch/Files/HomeFilesSearchViewController.m b/Riot/Modules/GlobalSearch/Files/HomeFilesSearchViewController.m index 84ab44030..04297d759 100644 --- a/Riot/Modules/GlobalSearch/Files/HomeFilesSearchViewController.m +++ b/Riot/Modules/GlobalSearch/Files/HomeFilesSearchViewController.m @@ -164,7 +164,7 @@ mxSession:session threadParameters:threadParameters presentationParameters:presentationParameters]; - + Analytics.shared.viewRoomTrigger = AnalyticsViewRoomTriggerFileSearch; [[AppDelegate theDelegate] showRoomWithParameters:parameters]; } diff --git a/Riot/Modules/GlobalSearch/Messages/HomeMessagesSearchViewController.m b/Riot/Modules/GlobalSearch/Messages/HomeMessagesSearchViewController.m index c3c42fb07..ea0c6a2f3 100644 --- a/Riot/Modules/GlobalSearch/Messages/HomeMessagesSearchViewController.m +++ b/Riot/Modules/GlobalSearch/Messages/HomeMessagesSearchViewController.m @@ -171,6 +171,7 @@ mxSession:self.mainSession threadParameters:threadParameters presentationParameters:screenParameters]; + Analytics.shared.viewRoomTrigger = AnalyticsViewRoomTriggerMessageSearch; [[LegacyAppDelegate theDelegate] showRoomWithParameters:parameters]; } diff --git a/Riot/Modules/GlobalSearch/Rooms/DirectoryViewController.m b/Riot/Modules/GlobalSearch/Rooms/DirectoryViewController.m index e0ab0f218..876d80cab 100644 --- a/Riot/Modules/GlobalSearch/Rooms/DirectoryViewController.m +++ b/Riot/Modules/GlobalSearch/Rooms/DirectoryViewController.m @@ -243,11 +243,13 @@ mxSession:mxSession threadParameters:nil presentationParameters:presentationParameters]; + Analytics.shared.viewRoomTrigger = AnalyticsViewRoomTriggerRoomDirectory; [[AppDelegate theDelegate] showRoomWithParameters:parameters]; } - (void)showRoomPreviewWithData:(RoomPreviewData*)roomPreviewData { + Analytics.shared.joinedRoomTrigger = AnalyticsJoinedRoomTriggerRoomDirectory; ScreenPresentationParameters *presentationParameters = [[ScreenPresentationParameters alloc] initWithRestoreInitialDisplay:NO stackAboveVisibleViews:NO]; RoomPreviewNavigationParameters *parameters = [[RoomPreviewNavigationParameters alloc] initWithPreviewData:roomPreviewData presentationParameters:presentationParameters]; diff --git a/Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m b/Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m index 5fd62ecad..93cabe850 100644 --- a/Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m +++ b/Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m @@ -460,6 +460,7 @@ - (void)showRoomWithId:(NSString*)roomId { + Analytics.shared.viewRoomTrigger = AnalyticsViewRoomTriggerRoomMemberDetail; [[AppDelegate theDelegate] showRoom:roomId andEventId:nil withMatrixSession:self.mainSession]; } diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index 6efc99584..861af60c0 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -1204,6 +1204,8 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; // Check if (roomAlias.length) { + Analytics.shared.joinedRoomTrigger = AnalyticsJoinedRoomTriggerSlashCommand; + // TODO: /join command does not support via parameters yet [self.mainSession joinRoom:roomAlias viaServers:nil success:^(MXRoom *room) { @@ -2323,6 +2325,8 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)parameters { + Analytics.shared.joinedRoomTrigger = AnalyticsJoinedRoomTriggerTimeline; + if (self.delegate) { return [self.delegate roomViewController:self handleUniversalLinkWithParameters:parameters]; @@ -3109,6 +3113,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; if (predecessorRoomId) { // Show predecessor room + Analytics.shared.viewRoomTrigger = AnalyticsViewRoomTriggerTombstone; [self showRoomWithId:predecessorRoomId]; } else diff --git a/Riot/Modules/Room/Search/RoomSearchViewController.m b/Riot/Modules/Room/Search/RoomSearchViewController.m index eba0ee508..235d89798 100644 --- a/Riot/Modules/Room/Search/RoomSearchViewController.m +++ b/Riot/Modules/Room/Search/RoomSearchViewController.m @@ -164,6 +164,7 @@ mxSession:self.mainSession threadParameters:threadParameters presentationParameters:screenParameters]; + Analytics.shared.viewRoomTrigger = AnalyticsViewRoomTriggerRoomSearch; [[LegacyAppDelegate theDelegate] showRoomWithParameters:parameters]; } diff --git a/Riot/Modules/SideMenu/SideMenuCoordinator.swift b/Riot/Modules/SideMenu/SideMenuCoordinator.swift index 7f5280fd8..7e3857d5f 100644 --- a/Riot/Modules/SideMenu/SideMenuCoordinator.swift +++ b/Riot/Modules/SideMenu/SideMenuCoordinator.swift @@ -309,6 +309,7 @@ final class SideMenuCoordinator: NSObject, SideMenuCoordinatorType { coordinator.toPresentable().dismiss(animated: true) { self.spaceSettingsCoordinator = nil + self.resetExploringSpaceIfNeeded() } } @@ -319,6 +320,12 @@ final class SideMenuCoordinator: NSObject, SideMenuCoordinatorType { self.spaceSettingsCoordinator = coordinator } + private func resetExploringSpaceIfNeeded() { + if sideMenuNavigationViewController.presentedViewController == nil { + Analytics.shared.exploringSpace = nil + } + } + // MARK: UserSessions management private func registerUserSessionsServiceNotifications() { @@ -407,8 +414,10 @@ extension SideMenuCoordinator: SpaceMenuPresenterDelegate { presenter.dismiss(animated: false) { switch action { case .exploreRooms: + Analytics.shared.viewRoomTrigger = .spaceMenu self.showExploreRooms(spaceId: spaceId, session: session) case .exploreMembers: + Analytics.shared.viewRoomTrigger = .spaceMenu self.showMembers(spaceId: spaceId, session: session) case .addRoom: session.spaceService.getSpace(withId: spaceId)?.canAddRoom { canAddRoom in @@ -453,6 +462,7 @@ extension SideMenuCoordinator: ExploreRoomCoordinatorDelegate { func exploreRoomCoordinatorDidComplete(_ coordinator: ExploreRoomCoordinatorType) { self.exploreRoomCoordinator?.toPresentable().dismiss(animated: true) { self.exploreRoomCoordinator = nil + self.resetExploringSpaceIfNeeded() } } } @@ -462,6 +472,7 @@ extension SideMenuCoordinator: SpaceMembersCoordinatorDelegate { func spaceMembersCoordinatorDidCancel(_ coordinator: SpaceMembersCoordinatorType) { self.membersCoordinator?.toPresentable().dismiss(animated: true) { self.membersCoordinator = nil + self.resetExploringSpaceIfNeeded() } } } @@ -472,7 +483,7 @@ extension SideMenuCoordinator: CreateRoomCoordinatorDelegate { coordinator.toPresentable().dismiss(animated: true) { self.createRoomCoordinator = nil self.parameters.appNavigator.sideMenu.dismiss(animated: true) { - + self.resetExploringSpaceIfNeeded() } if let spaceId = coordinator.parentSpace?.spaceId { self.parameters.appNavigator.navigate(to: .space(spaceId)) @@ -484,7 +495,7 @@ extension SideMenuCoordinator: CreateRoomCoordinatorDelegate { coordinator.toPresentable().dismiss(animated: true) { self.createRoomCoordinator = nil self.parameters.appNavigator.sideMenu.dismiss(animated: true) { - + self.resetExploringSpaceIfNeeded() } if let spaceId = coordinator.parentSpace?.spaceId { self.parameters.appNavigator.navigate(to: .space(spaceId)) @@ -495,6 +506,7 @@ extension SideMenuCoordinator: CreateRoomCoordinatorDelegate { func createRoomCoordinatorDidCancel(_ coordinator: CreateRoomCoordinatorType) { coordinator.toPresentable().dismiss(animated: true) { self.createRoomCoordinator = nil + self.resetExploringSpaceIfNeeded() } } } @@ -508,5 +520,6 @@ extension SideMenuCoordinator: UIAdaptivePresentationControllerDelegate { self.createSpaceCoordinator = nil self.createRoomCoordinator = nil self.spaceSettingsCoordinator = nil + self.resetExploringSpaceIfNeeded() } } diff --git a/Riot/Modules/Spaces/SpaceMembers/MemberDetail/SpaceMemberDetailViewModel.swift b/Riot/Modules/Spaces/SpaceMembers/MemberDetail/SpaceMemberDetailViewModel.swift index 114584869..cee72964d 100644 --- a/Riot/Modules/Spaces/SpaceMembers/MemberDetail/SpaceMemberDetailViewModel.swift +++ b/Riot/Modules/Spaces/SpaceMembers/MemberDetail/SpaceMemberDetailViewModel.swift @@ -59,6 +59,7 @@ final class SpaceMemberDetailViewModel: NSObject, SpaceMemberDetailViewModelType case .loadData: self.loadData() case .openRoom(let roomId): + Analytics.shared.viewRoomTrigger = .spaceMemberDetail self.coordinatorDelegate?.spaceMemberDetailViewModel(self, showRoomWithId: roomId) case .createRoom(let memberId): self.createDirectRoom(forMemberWithId: memberId) @@ -108,6 +109,7 @@ final class SpaceMemberDetailViewModel: NSObject, SpaceMemberDetailViewModelType } return } + Analytics.shared.viewRoomTrigger = .created self.coordinatorDelegate?.spaceMemberDetailViewModel(self, showRoomWithId: room.roomId) } } failure: { error in diff --git a/Riot/Modules/Spaces/SpaceMembers/MemberList/SpaceMemberListViewController.swift b/Riot/Modules/Spaces/SpaceMembers/MemberList/SpaceMemberListViewController.swift index c4419b870..dce516a80 100644 --- a/Riot/Modules/Spaces/SpaceMembers/MemberList/SpaceMemberListViewController.swift +++ b/Riot/Modules/Spaces/SpaceMembers/MemberList/SpaceMemberListViewController.swift @@ -75,6 +75,7 @@ final class SpaceMemberListViewController: RoomParticipantsViewController { super.viewWillAppear(animated) AnalyticsScreenTracker.trackScreen(.spaceMembers) + Analytics.shared.exploringSpace = viewModel.space } override var preferredStatusBarStyle: UIStatusBarStyle { diff --git a/Riot/Modules/Spaces/SpaceMembers/MemberList/SpaceMemberListViewModel.swift b/Riot/Modules/Spaces/SpaceMembers/MemberList/SpaceMemberListViewModel.swift index 91b555928..362bf56df 100644 --- a/Riot/Modules/Spaces/SpaceMembers/MemberList/SpaceMemberListViewModel.swift +++ b/Riot/Modules/Spaces/SpaceMembers/MemberList/SpaceMemberListViewModel.swift @@ -32,6 +32,9 @@ final class SpaceMemberListViewModel: SpaceMemberListViewModelType { // MARK: Public + var space: MXSpace? { + return session.spaceService.getSpace(withId: spaceId) + } weak var viewDelegate: SpaceMemberListViewModelViewDelegate? weak var coordinatorDelegate: SpaceMemberListViewModelCoordinatorDelegate? diff --git a/Riot/Modules/Spaces/SpaceMembers/MemberList/SpaceMemberListViewModelType.swift b/Riot/Modules/Spaces/SpaceMembers/MemberList/SpaceMemberListViewModelType.swift index 4b4a0e21c..3cbecf47f 100644 --- a/Riot/Modules/Spaces/SpaceMembers/MemberList/SpaceMemberListViewModelType.swift +++ b/Riot/Modules/Spaces/SpaceMembers/MemberList/SpaceMemberListViewModelType.swift @@ -33,6 +33,7 @@ protocol SpaceMemberListViewModelType { var viewDelegate: SpaceMemberListViewModelViewDelegate? { get set } var coordinatorDelegate: SpaceMemberListViewModelCoordinatorDelegate? { get set } + var space: MXSpace? { get } func process(viewAction: SpaceMemberListViewAction) } diff --git a/Riot/Modules/Spaces/SpaceMembers/SpaceMembersCoordinator.swift b/Riot/Modules/Spaces/SpaceMembers/SpaceMembersCoordinator.swift index 4b16e5f81..f9dde8858 100644 --- a/Riot/Modules/Spaces/SpaceMembers/SpaceMembersCoordinator.swift +++ b/Riot/Modules/Spaces/SpaceMembers/SpaceMembersCoordinator.swift @@ -127,6 +127,10 @@ final class SpaceMembersCoordinator: SpaceMembersCoordinatorType { let roomDataSourceManager = MXKRoomDataSourceManager.sharedManager(forMatrixSession: self.parameters.session) roomDataSourceManager?.roomDataSource(forRoom: roomId, create: true, onComplete: { [weak self] roomDataSource in + if let room = self?.parameters.session.room(withRoomId: roomId) { + Analytics.shared.trackViewRoom(room) + } + let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main) guard let roomViewController = storyboard.instantiateViewController(withIdentifier: "RoomViewControllerStoryboardId") as? RoomViewController else { return diff --git a/Riot/Modules/Spaces/SpaceRoomList/ExploreRoom/SpaceExploreRoomViewController.swift b/Riot/Modules/Spaces/SpaceRoomList/ExploreRoom/SpaceExploreRoomViewController.swift index bea9711f0..b19977e00 100644 --- a/Riot/Modules/Spaces/SpaceRoomList/ExploreRoom/SpaceExploreRoomViewController.swift +++ b/Riot/Modules/Spaces/SpaceRoomList/ExploreRoom/SpaceExploreRoomViewController.swift @@ -88,6 +88,15 @@ final class SpaceExploreRoomViewController: UIViewController { AnalyticsScreenTracker.trackScreen(.spaceExploreRooms) } + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + if let spaceRoom = self.viewModel.space?.room { + Analytics.shared.trackViewRoom(spaceRoom) + } + Analytics.shared.exploringSpace = self.viewModel.space + } + override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) diff --git a/Riot/Modules/Spaces/SpaceRoomList/ExploreRoom/SpaceExploreRoomViewModel.swift b/Riot/Modules/Spaces/SpaceRoomList/ExploreRoom/SpaceExploreRoomViewModel.swift index 3a3733118..57fd88f15 100644 --- a/Riot/Modules/Spaces/SpaceRoomList/ExploreRoom/SpaceExploreRoomViewModel.swift +++ b/Riot/Modules/Spaces/SpaceRoomList/ExploreRoom/SpaceExploreRoomViewModel.swift @@ -71,6 +71,9 @@ final class SpaceExploreRoomViewModel: SpaceExploreRoomViewModelType { } private var spaceGraphObserver: Any? + var space: MXSpace? { + return session.spaceService.getSpace(withId: spaceId) + } // MARK: Public diff --git a/Riot/Modules/Spaces/SpaceRoomList/ExploreRoom/SpaceExploreRoomViewModelType.swift b/Riot/Modules/Spaces/SpaceRoomList/ExploreRoom/SpaceExploreRoomViewModelType.swift index c545c6a54..5d22aa6f6 100644 --- a/Riot/Modules/Spaces/SpaceRoomList/ExploreRoom/SpaceExploreRoomViewModelType.swift +++ b/Riot/Modules/Spaces/SpaceRoomList/ExploreRoom/SpaceExploreRoomViewModelType.swift @@ -17,6 +17,7 @@ */ import Foundation +import MatrixSDK protocol SpaceExploreRoomViewModelViewDelegate: AnyObject { func spaceExploreRoomViewModel(_ viewModel: SpaceExploreRoomViewModelType, didUpdateViewState viewSate: SpaceExploreRoomViewState) @@ -37,6 +38,7 @@ protocol SpaceExploreRoomViewModelType { var viewDelegate: SpaceExploreRoomViewModelViewDelegate? { get set } var coordinatorDelegate: SpaceExploreRoomViewModelCoordinatorDelegate? { get set } var showCancelMenuItem: Bool { get } + var space: MXSpace? { get } func process(viewAction: SpaceExploreRoomViewAction) @available(iOS 13.0, *) diff --git a/Riot/Modules/Spaces/SpaceRoomList/ExploreRoomCoordinator.swift b/Riot/Modules/Spaces/SpaceRoomList/ExploreRoomCoordinator.swift index 71f560749..276edf745 100644 --- a/Riot/Modules/Spaces/SpaceRoomList/ExploreRoomCoordinator.swift +++ b/Riot/Modules/Spaces/SpaceRoomList/ExploreRoomCoordinator.swift @@ -116,6 +116,7 @@ final class ExploreRoomCoordinator: NSObject, ExploreRoomCoordinatorType { } private func showRoomPreview(with item: SpaceExploreRoomListItemViewData, from sourceView: UIView?) { + Analytics.shared.joinedRoomTrigger = .spaceHierarchy let coordinator = self.createShowSpaceRoomDetailCoordinator(session: self.session, childInfo: item.childInfo) coordinator.start() self.add(childCoordinator: coordinator) @@ -151,6 +152,11 @@ final class ExploreRoomCoordinator: NSObject, ExploreRoomCoordinatorType { let roomDataSourceManager = MXKRoomDataSourceManager.sharedManager(forMatrixSession: self.session) roomDataSourceManager?.roomDataSource(forRoom: roomId, create: true, onComplete: { [weak self] roomDataSource in + if let room = self?.session.room(withRoomId: roomId) { + Analytics.shared.viewRoomTrigger = .spaceHierarchy + Analytics.shared.trackViewRoom(room) + } + let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main) guard let roomViewController = storyboard.instantiateViewController(withIdentifier: "RoomViewControllerStoryboardId") as? RoomViewController else { return diff --git a/Riot/Modules/StartChat/StartChatViewController.m b/Riot/Modules/StartChat/StartChatViewController.m index 216de7b47..c70bbdc83 100644 --- a/Riot/Modules/StartChat/StartChatViewController.m +++ b/Riot/Modules/StartChat/StartChatViewController.m @@ -648,6 +648,7 @@ [self stopActivityIndicator]; + Analytics.shared.viewRoomTrigger = AnalyticsViewRoomTriggerCreated; [[AppDelegate theDelegate] showRoom:room.roomId andEventId:nil withMatrixSession:self.mainSession]; } failure:onFailure]; diff --git a/RiotSwiftUI/Modules/Spaces/SpaceSettings/Coordinator/SpaceSettingsModalCoordinator.swift b/RiotSwiftUI/Modules/Spaces/SpaceSettings/Coordinator/SpaceSettingsModalCoordinator.swift index a9bd120c7..d1f35c377 100644 --- a/RiotSwiftUI/Modules/Spaces/SpaceSettings/Coordinator/SpaceSettingsModalCoordinator.swift +++ b/RiotSwiftUI/Modules/Spaces/SpaceSettings/Coordinator/SpaceSettingsModalCoordinator.swift @@ -111,8 +111,10 @@ final class SpaceSettingsModalCoordinator: Coordinator { private func pushOptionScreen(ofType optionType: SpaceSettingsOptionType) { switch optionType { case .rooms: + Analytics.shared.viewRoomTrigger = .spaceSettings exploreRooms(ofSpaceWithId: self.parameters.spaceId) case .members: + Analytics.shared.viewRoomTrigger = .spaceSettings showMembers(ofSpaceWithId: self.parameters.spaceId) case .visibility: showAccess(ofSpaceWithId: self.parameters.spaceId) diff --git a/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Service/MatrixSDK/SpaceSettingsService.swift b/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Service/MatrixSDK/SpaceSettingsService.swift index bec782b3a..429f2e5a5 100644 --- a/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Service/MatrixSDK/SpaceSettingsService.swift +++ b/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Service/MatrixSDK/SpaceSettingsService.swift @@ -114,6 +114,10 @@ class SpaceSettingsService: SpaceSettingsServiceProtocol { userDefinedAddress = newValue } + func trackSpace() { + Analytics.shared.exploringSpace = session.spaceService.getSpace(withId: spaceId) + } + // MARK: - Private private func readRoomState() { diff --git a/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Service/Mock/MockSpaceSettingsService.swift b/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Service/Mock/MockSpaceSettingsService.swift index 1ddf6ea08..d58e980ad 100644 --- a/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Service/Mock/MockSpaceSettingsService.swift +++ b/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Service/Mock/MockSpaceSettingsService.swift @@ -53,4 +53,8 @@ class MockSpaceSettingsService: SpaceSettingsServiceProtocol { func simulateUpdate(addressValidationStatus: SpaceCreationSettingsAddressValidationStatus) { self.addressValidationSubject.value = addressValidationStatus } + + func trackSpace() { + + } } diff --git a/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Service/SpaceSettingsServiceProtocol.swift b/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Service/SpaceSettingsServiceProtocol.swift index 51775c8d6..3d0666047 100644 --- a/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Service/SpaceSettingsServiceProtocol.swift +++ b/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Service/SpaceSettingsServiceProtocol.swift @@ -34,6 +34,7 @@ protocol SpaceSettingsServiceProtocol: Avatarable { func update(roomName: String, topic: String, address: String, avatar: UIImage?, completion: ((_ result: SpaceSettingsServiceCompletionResult) -> Void)?) func addressDidChange(_ newValue: String) + func trackSpace() } // MARK: Avatarable diff --git a/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/SpaceSettingsModels.swift b/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/SpaceSettingsModels.swift index 86e606c0e..6ca32eef4 100644 --- a/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/SpaceSettingsModels.swift +++ b/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/SpaceSettingsModels.swift @@ -120,4 +120,5 @@ enum SpaceSettingsViewAction { case pickImage(_ sourceRect: CGRect) case optionSelected(_ optionType: SpaceSettingsOptionType) case addressChanged(_ newValue: String) + case trackSpace } diff --git a/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/SpaceSettingsViewModel.swift b/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/SpaceSettingsViewModel.swift index fc2771823..f2969bb86 100644 --- a/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/SpaceSettingsViewModel.swift +++ b/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/SpaceSettingsViewModel.swift @@ -123,6 +123,8 @@ class SpaceSettingsViewModel: SpaceSettingsViewModelType, SpaceSettingsViewModel } case .addressChanged(let newValue): service.addressDidChange(newValue) + case .trackSpace: + service.trackSpace() } } diff --git a/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/View/SpaceSettings.swift b/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/View/SpaceSettings.swift index c026ae358..9ad8bca8f 100644 --- a/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/View/SpaceSettings.swift +++ b/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/View/SpaceSettings.swift @@ -68,6 +68,9 @@ struct SpaceSettings: View { }), secondaryButton: .cancel()) }) + .onAppear { + viewModel.send(viewAction: .trackSpace) + } } // MARK: - Private