mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-10-31 16:24:11 +00:00
155 lines
6.5 KiB
Swift
155 lines
6.5 KiB
Swift
//
|
|
// Copyright 2026 Element Creations Ltd.
|
|
//
|
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
|
// Please see LICENSE files in the repository root for full details.
|
|
//
|
|
|
|
import AnalyticsEvents
|
|
|
|
/// A service responsible for managing analytics clients and sending events through them.
|
|
///
|
|
/// Events may include user activity, or app health data such as crashes,
|
|
/// non-fatal issues and performance.
|
|
///
|
|
/// ## Creating Analytics Events
|
|
///
|
|
/// Events are managed in a shared repo for all Element clients https://github.com/matrix-org/matrix-analytics-events
|
|
/// To add a new event create a PR to that repo with the new/updated schema. Once merged
|
|
/// into `main`, update the AnalyticsEvents Swift package in `project.yml`.
|
|
protocol AnalyticsServiceProtocol: AnyObject {
|
|
/// A signpost client for performance testing the app. This client doesn't respect the
|
|
/// `isRunning` state or behave any differently when `start`/`reset` are called.
|
|
var signpost: Signposter { get }
|
|
|
|
/// Whether to show the user the analytics opt in prompt.
|
|
var shouldShowAnalyticsPrompt: Bool { get }
|
|
|
|
/// Whether analytics tracking is currently enabled.
|
|
var isEnabled: Bool { get }
|
|
|
|
/// Opts in to analytics tracking.
|
|
func optIn()
|
|
|
|
/// Stops analytics tracking and calls `reset` to clear any IDs and event queues.
|
|
func optOut()
|
|
|
|
/// Starts the analytics client if the user has opted in, otherwise does nothing.
|
|
func startIfEnabled()
|
|
|
|
/// Resets the consent state for analytics.
|
|
func resetConsentState()
|
|
|
|
/// Track the presentation of a screen.
|
|
/// - Parameter screen: The screen that was shown.
|
|
/// - Parameter milliseconds: An optional value representing how long the screen was shown for in milliseconds.
|
|
func track(screen: AnalyticsEvent.MobileScreen.ScreenName, duration milliseconds: Int?)
|
|
func trackInteraction(index: Int?, name: AnalyticsEvent.Interaction.Name)
|
|
|
|
/// Track an analytics error event.
|
|
/// - Parameter context: Additional context or description for the error.
|
|
/// - Parameter domain: The domain to which the error belongs.
|
|
/// - Parameter name: The name of the error.
|
|
/// - Parameter timeToDecryptMillis: The time it took to decrypt the event in milliseconds. Only used for UTD errors; pass `nil` otherwise.
|
|
/// Can be found in `UnableToDecryptInfo`. If `UnableToDecryptInfo` contains `nil` for this value, pass `-1`.
|
|
func trackError(context: String?, domain: AnalyticsEvent.Error.Domain,
|
|
name: AnalyticsEvent.Error.Name,
|
|
timeToDecryptMillis: Int?,
|
|
eventLocalAgeMillis: Int?,
|
|
isFederated: Bool?,
|
|
isMatrixDotOrg: Bool?,
|
|
userTrustsOwnIdentity: Bool?,
|
|
wasVisibleToUser: Bool?)
|
|
|
|
/// Track the creation of a room.
|
|
/// - Parameter isDM: `true` if the created room is a direct message, `false` otherwise.
|
|
func trackCreatedRoom(isDM: Bool)
|
|
|
|
/// 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 to a message.
|
|
/// - messageType: The type of the message.
|
|
/// - startsThread: Whether the composer is used to start a new thread.
|
|
func trackComposer(inThread: Bool,
|
|
isEditing: Bool,
|
|
isReply: Bool,
|
|
messageType: AnalyticsEvent.Composer.MessageType,
|
|
startsThread: Bool?)
|
|
|
|
/// 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)
|
|
|
|
/// 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)
|
|
|
|
/// Track the action of creating a poll.
|
|
/// - Parameters:
|
|
/// - isUndisclosed: Whether the poll is undisclosed.
|
|
/// - numberOfAnswers: The number of options in the poll.
|
|
func trackPollCreated(isUndisclosed: Bool, numberOfAnswers: Int)
|
|
|
|
/// Track the action of voting on a poll.
|
|
func trackPollVote()
|
|
|
|
/// Track the action of ending a poll.
|
|
func trackPollEnd()
|
|
|
|
/// Track a room moderation action.
|
|
func trackRoomModeration(action: AnalyticsEvent.RoomModeration.Action, role: RoomRole?)
|
|
func trackSessionSecurityState(_ state: SessionSecurityState)
|
|
func updateUserProperties(_ userProperties: AnalyticsEvent.UserProperties)
|
|
func trackPinUnpinEvent(_ event: AnalyticsEvent.PinUnpinAction)
|
|
}
|
|
|
|
// sourcery: AutoMockable
|
|
extension AnalyticsServiceProtocol {
|
|
func track(screen: AnalyticsEvent.MobileScreen.ScreenName) {
|
|
track(screen: screen, duration: nil)
|
|
}
|
|
|
|
func trackInteraction(name: AnalyticsEvent.Interaction.Name) {
|
|
trackInteraction(index: nil, name: name)
|
|
}
|
|
|
|
@_disfavoredOverload // make sure this doesn't cause infinite recursion
|
|
func trackError(context: String?,
|
|
domain: AnalyticsEvent.Error.Domain,
|
|
name: AnalyticsEvent.Error.Name,
|
|
timeToDecryptMillis: Int? = nil,
|
|
eventLocalAgeMillis: Int? = nil,
|
|
isFederated: Bool? = nil,
|
|
isMatrixDotOrg: Bool? = nil,
|
|
userTrustsOwnIdentity: Bool? = nil,
|
|
wasVisibleToUser: Bool? = nil) {
|
|
trackError(context: context,
|
|
domain: domain,
|
|
name: name,
|
|
timeToDecryptMillis: timeToDecryptMillis,
|
|
eventLocalAgeMillis: eventLocalAgeMillis,
|
|
isFederated: isFederated,
|
|
isMatrixDotOrg: isMatrixDotOrg,
|
|
userTrustsOwnIdentity: userTrustsOwnIdentity,
|
|
wasVisibleToUser: wasVisibleToUser)
|
|
}
|
|
|
|
func trackComposer(inThread: Bool,
|
|
isEditing: Bool,
|
|
isReply: Bool,
|
|
startsThread: Bool?) {
|
|
trackComposer(inThread: inThread,
|
|
isEditing: isEditing,
|
|
isReply: isReply,
|
|
messageType: .Text,
|
|
startsThread: startsThread)
|
|
}
|
|
}
|