mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-05-03 14:46:56 +02:00
Use matrix-analytics-events generated stubs (locally for now).
Track screens, removing any that aren't part of the schema.
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
//
|
||||
|
||||
import PostHog
|
||||
import AnalyticsEvents
|
||||
|
||||
@objcMembers class Analytics: NSObject {
|
||||
|
||||
@@ -112,18 +113,19 @@ import PostHog
|
||||
postHog?.flush()
|
||||
}
|
||||
|
||||
func log(event: String) {
|
||||
postHog?.capture(event)
|
||||
private func capture(event: DictionaryConvertible, named eventName: String) {
|
||||
postHog?.capture(eventName, properties: event.dictionary)
|
||||
}
|
||||
|
||||
func trackScreen(_ screenName: String) {
|
||||
// postHog?.capture("screen:\(screenName)")
|
||||
func trackScreen(_ screen: AnalyticsScreen) {
|
||||
let event = AnalyticsEventScreen(durationMs: nil, eventName: .screen, screenName: screen.screenName)
|
||||
capture(event: event, named: event.eventName.rawValue)
|
||||
}
|
||||
|
||||
func trackE2EEError(_ reason: DecryptionFailureReason, count: Int) {
|
||||
for _ in 0..<count {
|
||||
let event = AnalyticsEvent.Error(domain: .E2EE, name: reason.errorName, context: nil)
|
||||
postHog?.capture("\(type(of: event).self)", properties: event.dictionary)
|
||||
let event = AnalyticsEventError(context: nil, domain: .e2Ee, eventName: .error, name: reason.errorName)
|
||||
capture(event: event, named: event.eventName.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,31 +139,34 @@ extension Analytics: MXAnalyticsDelegate {
|
||||
func trackDuration(_ seconds: TimeInterval, category: String, name: String) { }
|
||||
|
||||
func trackCallStarted(_ call: MXCall) {
|
||||
let event = AnalyticsEvent.CallStarted(placed: !call.isIncoming,
|
||||
isVideo: call.isVideoCall,
|
||||
numParticipants: Int(call.room.summary.membersCount.joined))
|
||||
let event = AnalyticsEventCallStarted(eventName: .callStarted,
|
||||
isVideo: call.isVideoCall,
|
||||
numParticipants: Int(call.room.summary.membersCount.joined),
|
||||
placed: !call.isIncoming)
|
||||
|
||||
postHog?.capture("\(type(of: event).self)", properties: event.dictionary)
|
||||
capture(event: event, named: event.eventName.rawValue)
|
||||
}
|
||||
|
||||
func trackCallEnded(_ call: MXCall) {
|
||||
let event = AnalyticsEvent.CallEnded(placed: !call.isIncoming,
|
||||
isVideo: call.isVideoCall,
|
||||
durationMs: Int(call.duration),
|
||||
numParticipants: Int(call.room.summary.membersCount.joined))
|
||||
let event = AnalyticsEventCallEnded(durationMs: Int(call.duration),
|
||||
eventName: .callEnded,
|
||||
isVideo: call.isVideoCall,
|
||||
numParticipants: Int(call.room.summary.membersCount.joined),
|
||||
placed: !call.isIncoming)
|
||||
|
||||
postHog?.capture("\(type(of: event).self)", properties: event.dictionary)
|
||||
capture(event: event, named: event.eventName.rawValue)
|
||||
}
|
||||
|
||||
func trackCallError(_ call: MXCall, with reason: __MXCallHangupReason) {
|
||||
let callEvent = AnalyticsEvent.CallError(placed: !call.isIncoming,
|
||||
isVideo: call.isVideoCall,
|
||||
numParticipants: Int(call.room.summary.membersCount.joined))
|
||||
let callEvent = AnalyticsEventCallError(eventName: .callError,
|
||||
isVideo: call.isVideoCall,
|
||||
numParticipants: Int(call.room.summary.membersCount.joined),
|
||||
placed: !call.isIncoming)
|
||||
|
||||
let event = AnalyticsEvent.Error(domain: .VOIP, name: reason.errorName, context: nil)
|
||||
let event = AnalyticsEventError(context: nil, domain: .voip, eventName: .error, name: reason.errorName)
|
||||
|
||||
postHog?.capture("\(type(of: callEvent).self)", properties: callEvent.dictionary)
|
||||
postHog?.capture("\(type(of: event).self)", properties: event.dictionary)
|
||||
capture(event: callEvent, named: callEvent.eventName.rawValue)
|
||||
capture(event: event, named: event.eventName.rawValue)
|
||||
}
|
||||
|
||||
func trackContactsAccessGranted(_ granted: Bool) {
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// Copyright 2021 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 AnalyticsScreen: Int {
|
||||
case group
|
||||
case home
|
||||
case myGroups
|
||||
case room
|
||||
case roomDirectory
|
||||
case user
|
||||
|
||||
var screenName: AnalyticsEventScreenName {
|
||||
switch self {
|
||||
case .group:
|
||||
return .group
|
||||
case .home:
|
||||
return .home
|
||||
case .myGroups:
|
||||
return .myGroups
|
||||
case .room:
|
||||
return .room
|
||||
case .roomDirectory:
|
||||
return .roomDirectory
|
||||
case .user:
|
||||
return .user
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,27 +16,28 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
protocol DictionaryConvertible {
|
||||
protocol DictionaryConvertible: Encodable {
|
||||
var dictionary: [String: Any] { get }
|
||||
}
|
||||
|
||||
extension DictionaryConvertible {
|
||||
var dictionary: [String: Any] {
|
||||
let mirror = Mirror(reflecting: self)
|
||||
let dict: [String: Any] = Dictionary(uniqueKeysWithValues: mirror.children
|
||||
.compactMap { (label: String?, value: Any) in
|
||||
guard let label = label else { return nil }
|
||||
|
||||
if let value = value as? NSCoding {
|
||||
return (label, value)
|
||||
}
|
||||
|
||||
if let value = value as? CustomStringConvertible {
|
||||
return (label, value.description)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
let dict: [String: Any] = Dictionary(uniqueKeysWithValues: mirror.children.compactMap { (label: String?, value: Any) in
|
||||
guard let label = label else { return nil }
|
||||
|
||||
// Handle standard types such as String/Int/Bool
|
||||
if let value = value as? NSCoding {
|
||||
return (label, value)
|
||||
}
|
||||
|
||||
// AnalyticsEvent enums
|
||||
if let value = value as? CustomStringConvertible {
|
||||
return (label, value.description)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return dict
|
||||
}
|
||||
|
||||
@@ -15,60 +15,70 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import AnalyticsEvents
|
||||
|
||||
// MARK: -Events
|
||||
// MARK: - Events
|
||||
//
|
||||
// All events must conform to DictionaryConvertible to be captured by PostHog
|
||||
|
||||
extension AnalyticsEvent.Error: DictionaryConvertible { }
|
||||
extension AnalyticsEvent.CallStarted: DictionaryConvertible { }
|
||||
extension AnalyticsEvent.CallEnded: DictionaryConvertible { }
|
||||
extension AnalyticsEvent.CallError: DictionaryConvertible { }
|
||||
extension AnalyticsEventError: DictionaryConvertible { }
|
||||
extension AnalyticsEventCallStarted: DictionaryConvertible { }
|
||||
extension AnalyticsEventCallEnded: DictionaryConvertible { }
|
||||
extension AnalyticsEventCallError: DictionaryConvertible { }
|
||||
extension AnalyticsEventScreen: DictionaryConvertible { }
|
||||
|
||||
// MARK: - Enums
|
||||
//
|
||||
// All enums must conform to CustomStringConvertible for DictionaryConvertible to access the raw value
|
||||
|
||||
extension AnalyticsEvent.ErrorDomain: CustomStringConvertible {
|
||||
var description: String { rawValue }
|
||||
extension AnalyticsEventErrorDomain: CustomStringConvertible {
|
||||
public var description: String { rawValue }
|
||||
}
|
||||
|
||||
extension AnalyticsEvent.ErrorName: CustomStringConvertible {
|
||||
var description: String { rawValue }
|
||||
extension AnalyticsEventErrorName: CustomStringConvertible {
|
||||
public var description: String { rawValue }
|
||||
}
|
||||
|
||||
extension AnalyticsEventScreenName: CustomStringConvertible {
|
||||
public var description: String { rawValue }
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
extension __MXCallHangupReason {
|
||||
var errorName: AnalyticsEvent.ErrorName {
|
||||
var errorName: AnalyticsEventErrorName {
|
||||
switch self {
|
||||
case .userHangup:
|
||||
return .VoipUserHangup
|
||||
return .voipUserHangup
|
||||
case .inviteTimeout:
|
||||
return .VoipInviteTimeout
|
||||
return .voipInviteTimeout
|
||||
case .iceFailed:
|
||||
return .VoipIceFailed
|
||||
return .voipIceFailed
|
||||
case .iceTimeout:
|
||||
return .VoipIceTimeout
|
||||
return .voipIceTimeout
|
||||
case .userMediaFailed:
|
||||
return .VoipUserMediaFailed
|
||||
return .voipUserMediaFailed
|
||||
case .unknownError:
|
||||
return .UnknownError
|
||||
return .unknownError
|
||||
default:
|
||||
return .UnknownError
|
||||
return .unknownError
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension DecryptionFailureReason {
|
||||
var errorName: AnalyticsEvent.ErrorName {
|
||||
var errorName: AnalyticsEventErrorName {
|
||||
switch self {
|
||||
case .unspecified:
|
||||
return .OlmUnspecifiedError
|
||||
return .olmUnspecifiedError
|
||||
case .olmKeysNotSent:
|
||||
return .OlmKeysNotSentError
|
||||
return .olmKeysNotSentError
|
||||
case .olmIndexError:
|
||||
return .OlmIndexError
|
||||
return .olmIndexError
|
||||
case .unexpected:
|
||||
return .UnknownError
|
||||
return .unknownError
|
||||
default:
|
||||
return .UnknownError
|
||||
return .unknownError
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
import Foundation
|
||||
|
||||
struct AnalyticsEvent {
|
||||
struct Error {
|
||||
let domain: ErrorDomain
|
||||
let name: ErrorName
|
||||
let context: String?
|
||||
}
|
||||
|
||||
enum ErrorDomain: String {
|
||||
case E2EE
|
||||
case VOIP
|
||||
}
|
||||
|
||||
enum ErrorName: String {
|
||||
case UnknownError
|
||||
case OlmIndexError
|
||||
case OlmKeysNotSentError
|
||||
case OlmUnspecifiedError
|
||||
case VoipUserHangup
|
||||
case VoipIceFailed
|
||||
case VoipInviteTimeout
|
||||
case VoipIceTimeout
|
||||
case VoipUserMediaFailed
|
||||
}
|
||||
|
||||
struct CallStarted {
|
||||
let placed: Bool
|
||||
let isVideo: Bool
|
||||
let numParticipants: Int
|
||||
}
|
||||
|
||||
struct CallEnded {
|
||||
let placed: Bool
|
||||
let isVideo: Bool
|
||||
let durationMs: Int
|
||||
let numParticipants: Int
|
||||
}
|
||||
|
||||
struct CallError {
|
||||
let placed: Bool
|
||||
let isVideo: Bool
|
||||
let numParticipants: Int
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user