From 6d5652d56aed0cc6b586172cdd42de2d1e360bc1 Mon Sep 17 00:00:00 2001 From: Nicolas Mauri Date: Wed, 21 Jun 2023 18:00:33 +0200 Subject: [PATCH] Add posthog events (#1097) --- .../RoomFlowCoordinator.swift | 3 +- .../InvitesScreen/View/InvitesScreen.swift | 1 + .../View/RoomDetailsEditScreen.swift | 1 + .../View/RoomDetailsScreen.swift | 1 + .../View/RoomMemberDetailsScreen.swift | 1 + .../View/RoomMembersListScreen.swift | 1 + .../RoomScreen/RoomScreenViewModel.swift | 35 +++++++++++++++---- .../Services/Analytics/Analytics.swift | 31 ++++++++++++++++ .../Sources/Services/Room/RoomProxy.swift | 4 ++- changelog.d/1097.feature | 1 + 10 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 changelog.d/1097.feature diff --git a/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift index 3a175096d..cc659125a 100644 --- a/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift @@ -231,7 +231,6 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { } } - /// Updates the navigation stack so it displays the timeline for the given room /// - Parameters: /// - roomID: the identifier of the room that is to be presented @@ -283,6 +282,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { mediaProvider: userSession.mediaProvider) self.timelineController = timelineController + ServiceLocator.shared.analytics.trackViewRoom(isDM: roomProxy.isDirect, isSpace: roomProxy.isSpace) + let parameters = RoomScreenCoordinatorParameters(roomProxy: roomProxy, timelineController: timelineController, mediaProvider: userSession.mediaProvider, diff --git a/ElementX/Sources/Screens/InvitesScreen/View/InvitesScreen.swift b/ElementX/Sources/Screens/InvitesScreen/View/InvitesScreen.swift index c82b1cf19..179d2c816 100644 --- a/ElementX/Sources/Screens/InvitesScreen/View/InvitesScreen.swift +++ b/ElementX/Sources/Screens/InvitesScreen/View/InvitesScreen.swift @@ -37,6 +37,7 @@ struct InvitesScreen: View { .background(Color.compound.bgCanvasDefault.ignoresSafeArea()) .navigationTitle(L10n.actionInvitesList) .alert(item: $context.alertInfo) + .track(screen: .invites) } // MARK: - Private diff --git a/ElementX/Sources/Screens/RoomDetailsEditScreen/View/RoomDetailsEditScreen.swift b/ElementX/Sources/Screens/RoomDetailsEditScreen/View/RoomDetailsEditScreen.swift index 03e85c086..b177a7ba2 100644 --- a/ElementX/Sources/Screens/RoomDetailsEditScreen/View/RoomDetailsEditScreen.swift +++ b/ElementX/Sources/Screens/RoomDetailsEditScreen/View/RoomDetailsEditScreen.swift @@ -36,6 +36,7 @@ struct RoomDetailsEditScreen: View { .navigationTitle(L10n.screenRoomDetailsEditRoomTitle) .navigationBarTitleDisplayMode(.inline) .toolbar { toolbar } + .track(screen: .roomSettings) } // MARK: - Private diff --git a/ElementX/Sources/Screens/RoomDetailsScreen/View/RoomDetailsScreen.swift b/ElementX/Sources/Screens/RoomDetailsScreen/View/RoomDetailsScreen.swift index 8c9fc63fc..83a5efe72 100644 --- a/ElementX/Sources/Screens/RoomDetailsScreen/View/RoomDetailsScreen.swift +++ b/ElementX/Sources/Screens/RoomDetailsScreen/View/RoomDetailsScreen.swift @@ -60,6 +60,7 @@ struct RoomDetailsScreen: View { } } } + .track(screen: .roomDetails) } // MARK: - Private diff --git a/ElementX/Sources/Screens/RoomMemberDetailsScreen/View/RoomMemberDetailsScreen.swift b/ElementX/Sources/Screens/RoomMemberDetailsScreen/View/RoomMemberDetailsScreen.swift index 4cbb7e5af..e347c8858 100644 --- a/ElementX/Sources/Screens/RoomMemberDetailsScreen/View/RoomMemberDetailsScreen.swift +++ b/ElementX/Sources/Screens/RoomMemberDetailsScreen/View/RoomMemberDetailsScreen.swift @@ -30,6 +30,7 @@ struct RoomMemberDetailsScreen: View { .elementFormStyle() .alert(item: $context.ignoreUserAlert, actions: blockUserAlertActions, message: blockUserAlertMessage) .alert(item: $context.alertInfo) + .track(screen: .user) } // MARK: - Private diff --git a/ElementX/Sources/Screens/RoomMemberListScreen/View/RoomMembersListScreen.swift b/ElementX/Sources/Screens/RoomMemberListScreen/View/RoomMembersListScreen.swift index 55857009d..dea7f93a7 100644 --- a/ElementX/Sources/Screens/RoomMemberListScreen/View/RoomMembersListScreen.swift +++ b/ElementX/Sources/Screens/RoomMemberListScreen/View/RoomMembersListScreen.swift @@ -39,6 +39,7 @@ struct RoomMembersListScreen: View { inviteButton } } + .track(screen: .roomMembers) } // MARK: - Private diff --git a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift index ee0bbbe33..f2b9e2144 100644 --- a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift @@ -60,6 +60,8 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol } buildTimelineViews() + + trackComposerMode() } // MARK: - Public @@ -86,9 +88,9 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol case .sendReaction(let emoji, let itemId): Task { await timelineController.sendReaction(emoji, to: itemId) } case .cancelReply: - state.composerMode = .default + setComposerMode(.default) case .cancelEdit: - state.composerMode = .default + setComposerMode(.default) state.bindings.composerText = "" case .markRoomAsRead: Task { await markRoomAsRead() } @@ -279,7 +281,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol let currentComposerState = state.composerMode state.bindings.composerText = "" - state.composerMode = .default + setComposerMode(.default) switch currentComposerState { case .reply(let itemId, _): @@ -291,6 +293,27 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol } } + private func setComposerMode(_ mode: RoomScreenComposerMode) { + guard mode != state.composerMode else { return } + state.composerMode = mode + trackComposerMode() + } + + private func trackComposerMode() { + var isEdit = false + var isReply = false + switch state.composerMode { + case .edit: + isEdit = true + case .reply: + isReply = true + default: + break + } + + ServiceLocator.shared.analytics.trackComposer(inThread: false, isEditing: isEdit, isReply: isReply, startsThread: nil) + } + private func displayError(_ type: RoomScreenErrorType) { switch type { case .alert(let message): @@ -380,7 +403,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol state.bindings.composerFocused = true state.bindings.composerText = messageTimelineItem.body - state.composerMode = .edit(originalItemId: messageTimelineItem.id) + setComposerMode(.edit(originalItemId: messageTimelineItem.id)) case .quote: guard let messageTimelineItem = timelineItem as? EventBasedMessageTimelineItemProtocol else { return @@ -404,7 +427,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol let replyDetails = TimelineItemReplyDetails.loaded(sender: eventTimelineItem.sender, contentType: buildReplyContent(for: eventTimelineItem)) - state.composerMode = .reply(itemID: eventTimelineItem.id, replyDetails: replyDetails) + setComposerMode(.reply(itemID: eventTimelineItem.id, replyDetails: replyDetails)) case .forward(let itemID): callback?(.displayMessageForwarding(itemID: itemID)) case .viewSource: @@ -420,7 +443,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol } if action.switchToDefaultComposer { - state.composerMode = .default + setComposerMode(.default) } } diff --git a/ElementX/Sources/Services/Analytics/Analytics.swift b/ElementX/Sources/Services/Analytics/Analytics.swift index 868d924fc..b57c080bd 100644 --- a/ElementX/Sources/Services/Analytics/Analytics.swift +++ b/ElementX/Sources/Services/Analytics/Analytics.swift @@ -131,4 +131,35 @@ extension Analytics { func trackCreatedRoom(isDM: Bool) { capture(event: AnalyticsEvent.CreatedRoom(isDM: isDM)) } + + /// Track the composer + /// - Parameters: + /// - inThread: whether the composer is used in a Thread + /// - isEditing: whether the composer is used to edit a message + /// - isReply: whether the composer is used to reply a message + /// - startsThread: whether the composer is used to start a new thread + func trackComposer(inThread: Bool, isEditing: Bool, isReply: Bool, startsThread: Bool?) { + capture(event: AnalyticsEvent.Composer(inThread: inThread, isEditing: isEditing, isReply: isReply, startsThread: startsThread)) + } + + /// Track the presentation of a room + /// - Parameters: + /// - isDM: whether the room is a direct message + /// - isSpace: whether the room is a space + func trackViewRoom(isDM: Bool, isSpace: Bool) { + capture(event: AnalyticsEvent.ViewRoom(activeSpace: nil, isDM: isDM, isSpace: isSpace, trigger: nil, viaKeyboard: nil)) + } + + /// Track the action of joining a room + /// - Parameters: + /// - isDM: whether the room is a direct message + /// - isSpace: whether the room is a space + /// - activeMemberCount: the number of active members in the room + func trackJoinedRoom(isDM: Bool, isSpace: Bool, activeMemberCount: UInt) { + guard let roomSize = AnalyticsEvent.JoinedRoom.RoomSize(memberCount: activeMemberCount) else { + MXLog.error("invalid room size") + return + } + capture(event: AnalyticsEvent.JoinedRoom(isDM: isDM, isSpace: isSpace, roomSize: roomSize, trigger: nil)) + } } diff --git a/ElementX/Sources/Services/Room/RoomProxy.swift b/ElementX/Sources/Services/Room/RoomProxy.swift index 926f7b5ee..d8455bacf 100644 --- a/ElementX/Sources/Services/Room/RoomProxy.swift +++ b/ElementX/Sources/Services/Room/RoomProxy.swift @@ -506,7 +506,9 @@ class RoomProxy: RoomProxyProtocol { func acceptInvitation() async -> Result { await Task.dispatch(on: .global()) { do { - return try .success(self.room.acceptInvitation()) + try self.room.acceptInvitation() + ServiceLocator.shared.analytics.trackJoinedRoom(isDM: self.room.isDirect(), isSpace: self.room.isSpace(), activeMemberCount: UInt(self.room.activeMembersCount())) + return .success(()) } catch { return .failure(.failedAcceptingInvite) } diff --git a/changelog.d/1097.feature b/changelog.d/1097.feature new file mode 100644 index 000000000..bfdfca6d9 --- /dev/null +++ b/changelog.d/1097.feature @@ -0,0 +1 @@ +Add analytics events.