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:
Doug
2021-11-24 18:04:54 +00:00
parent b5f3a56666
commit cea6cd145b
45 changed files with 137 additions and 232 deletions
+26 -21
View File
@@ -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
}
+33 -23
View File
@@ -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
}
}