Skip to content

Commit

Permalink
feat: move entire AnalyticsManager to KeyAppKit
Browse files Browse the repository at this point in the history
  • Loading branch information
bigearsenal committed Jul 28, 2023
1 parent 0d33afd commit 2b0f6d6
Show file tree
Hide file tree
Showing 19 changed files with 141 additions and 163 deletions.
9 changes: 8 additions & 1 deletion Packages/KeyAppKit/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ let package = Package(
.package(url: "https://github.com/attaswift/BigInt.git", from: "5.3.0"),
.package(url: "https://github.com/p2p-org/BigDecimal.git", branch: "main"),
.package(url: "https://github.com/vapor/websocket-kit", from: "2.8.0"),
.package(url: "https://github.com/amplitude/Amplitude-iOS.git", from: "8.15.0"),
.package(url: "https://github.com/AppsFlyerSDK/AppsFlyerFramework", from: "6.12.0"),
.package(url: "https://github.com/firebase/firebase-ios-sdk.git", from: "10.7.0"),
],
targets: [
.binaryTarget(
Expand Down Expand Up @@ -167,7 +170,11 @@ let package = Package(
// AnalyticsManager
.target(
name: "AnalyticsManager",
dependencies: []
dependencies: [
.product(name: "Amplitude", package: "Amplitude-iOS"),
.product(name: "AppsFlyerLib", package: "AppsFlyerFramework"),
.product(name: "FirebaseAnalytics", package: "firebase-ios-sdk"),
]
),
.testTarget(
name: "AnalyticsManagerUnitTests",
Expand Down
15 changes: 4 additions & 11 deletions Packages/KeyAppKit/Sources/AnalyticsManager/AnalyticsManager.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
//
// AnalyticsManager .swift
// p2p_wallet
//
// Created by Chung Tran on 11/06/2021.
//

import Foundation

public protocol AnalyticsManager {
Expand All @@ -14,7 +7,7 @@ public protocol AnalyticsManager {

public class AnalyticsManagerImpl: AnalyticsManager {
private let providers: [AnalyticsProvider]

public init(providers: [AnalyticsProvider]) {
self.providers = providers
}
Expand All @@ -24,18 +17,18 @@ public class AnalyticsManagerImpl: AnalyticsManager {
// fillter providers to send
guard event.providerIds.contains(provider.providerId)
else { return }

// log event to provider
provider.logEvent(event)
}
}

public func log(parameter: AnalyticsParameter) {
providers.forEach { provider in
// fillter providers to send
guard parameter.providerIds.contains(provider.providerId)
else { return }

// log event to provider
provider.logParameter(parameter)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation
import Amplitude
import Foundation

extension AmplitudeAnalyticsProvider {
public extension AmplitudeAnalyticsProvider {
func setUserId(_ id: String?) {
guard let id else { return }
Amplitude.instance().setUserId(id)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
//
// AnalyticsService.swift
// p2p_wallet
//
// Created by Ivan on 12.12.2022.
//

import Foundation
import AnalyticsManager
import Foundation

extension AnalyticsManager {
public extension AnalyticsManager {
func log(event: KeyAppAnalyticsEvent) {
log(event: event as AnalyticsEvent)
}

func log(parameter: KeyAppAnalyticsParameter) {
log(parameter: parameter as AnalyticsParameter)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import Foundation

extension String {
var snakeAndFirstUppercased: String? {
guard let snakeCase = snakeCased() else { return nil }
return snakeCase.prefix(1).uppercased() + snakeCase.dropFirst()
}

private func snakeCased() -> String? {
let pattern = "([a-z0-9])([A-Z])"

let regex = try? NSRegularExpression(pattern: pattern, options: [])
let range = NSRange(location: 0, length: count)
return regex?.stringByReplacingMatches(in: self, options: [], range: range, withTemplate: "$1_$2")
.uppercaseFirst
}

private var uppercaseFirst: String {
firstCharacter.uppercased() + String(dropFirst())
}

private var firstCharacter: String {
String(prefix(1))
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import Foundation
import AnalyticsManager
import Foundation

extension KeyAppAnalyticsEvent {

public extension KeyAppAnalyticsEvent {
/// The name of the event to send
var name: String? {
// By default, name of the event will be converted from `camelCase` to `Uppercased_Snake_Case` format
// For example: `KeyAppAnalyticsEvent.mainScreenSwapOpen` will be converted to "Main_Screen_Swap_Open" automatically.

// For example: `KeyAppAnalyticsEvent.mainScreenSwapOpen` will be converted to "Main_Screen_Swap_Open"
// automatically.

// Modify the name manually and prevent default behavior
switch self {
case .sellOnlySOLNotification:
Expand All @@ -23,17 +23,18 @@ extension KeyAppAnalyticsEvent {
default:
break
}

// Default converter from `camelCase` to `Uppercased_Snake_Case` format
return mirror.label.snakeAndFirstUppercased
}

/// Params sent with event
var params: [String: Any]? {
guard !mirror.params.isEmpty else { return nil }

// The same for params, params key & value can be customized too, if not, it will be automatically converted to `Uppercased_Snake_Case`


// The same for params, params key & value can be customized too, if not, it will be automatically converted to
// `Uppercased_Snake_Case`

// Modify the key & value manually and prevent default behavior
switch self {
case let .swapChangingTokenAClick(tokenAName):
Expand All @@ -43,19 +44,23 @@ extension KeyAppAnalyticsEvent {
case let .swapChangingValueTokenA(tokenAName, tokenAValue):
return ["Token_A_Name": tokenAName, "Token_A_Value": tokenAValue]
case let .swapChangingValueTokenB(tokenBName, tokenBValue, transactionSimulation):
return ["Token_B_Name": tokenBName, "Token_B_Value": tokenBValue, "Transaction_Simulation": transactionSimulation]
return [
"Token_B_Name": tokenBName,
"Token_B_Value": tokenBValue,
"Transaction_Simulation": transactionSimulation,
]
case let .swapChangingValueTokenAAll(tokenAName, tokenAValue):
return ["Token_A_Name": tokenAName, "Token_A_Value": tokenAValue]
case let .swapSwitchTokens(tokenAName, tokenBName):
return ["Token_A_Name": tokenAName, "Token_B_Name": tokenBName]
default:
break
}

// Default converter from `camelCase` to `Uppercased_Snake_Case` format
let formatted = mirror.params.map {
var key = $0.key.snakeAndFirstUppercased

switch key {
case "Token_BName":
key = "Token_B_Name"
Expand All @@ -68,7 +73,7 @@ extension KeyAppAnalyticsEvent {
default:
break
}

return (key ?? "", $0.value)
}
return Dictionary(uniqueKeysWithValues: formatted)
Expand All @@ -78,33 +83,33 @@ extension KeyAppAnalyticsEvent {
var providerIds: [AnalyticsProviderId] {
// By default, all events will be sent to amplitude only
var ids: [KeyAppAnalyticsProviderId] = [
.amplitude
.amplitude,
]

// for some events, we will sent to appsFlyer and firebaseAnalytics
switch self {
case .onboardingStartButton,
.creationPhoneScreen,
.createSmsValidation,
.createConfirmPin,
.usernameCreationScreen,
.usernameCreationButton,
.restoreSeed,
.onboardingMerged,
.login,
.buyButtonPressed,
.sendNewConfirmButtonClick,
.swapClickApproveButton:
.creationPhoneScreen,
.createSmsValidation,
.createConfirmPin,
.usernameCreationScreen,
.usernameCreationButton,
.restoreSeed,
.onboardingMerged,
.login,
.buyButtonPressed,
.sendNewConfirmButtonClick,
.swapClickApproveButton:
ids.append(contentsOf: [
.appsFlyer,
.firebaseAnalytics
.firebaseAnalytics,
])
default:
break
}
return ids.map(\.rawValue)
}

// MARK: - Helpers

private var mirror: (label: String, params: [String: Any]) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import AnalyticsManager
import Foundation

enum KeyAppAnalyticsEvent: AnalyticsEvent {
public enum KeyAppAnalyticsEvent: AnalyticsEvent {
// MARK: - Create wallet

case createPhoneClickButton
Expand Down Expand Up @@ -42,25 +42,25 @@ enum KeyAppAnalyticsEvent: AnalyticsEvent {
case mainScreenTokenDetailsOpen(tokenTicker: String)
case mainScreenBuyToken(tokenName: String)
case mainScreenHiddenTokens

case mainScreenCryptoClick
case mainScreenSendClick
case mainScreenHistoryClick
case mainScreenSettingsClick

case userAggregateBalanceBase(amountUsd: Double, currency: String)
case userHasPositiveBalanceBase(state: Bool)

// MARK: - Crypto

case cryptoScreenOpened
case cryptoAmountClick
case cryptoReceiveClick
case cryptoSwapClick
case cryptoTokenClick(tokenName: String)
case cryptoClaimTransferredViewed(claimCount: Int)
case cryptoClaimTransferredClick

case userAggregateBalanceTokens(amountUsd: Double, currency: String)
case userHasPositiveBalanceTokens(state: Bool)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import Foundation
import AnalyticsManager
import Foundation

extension KeyAppAnalyticsParameter {
public extension KeyAppAnalyticsParameter {
var name: String? {
mirror.label.snakeAndFirstUppercased
}

var value: Any? {
mirror.value
}

var providerIds: [AnalyticsProviderId] {
[KeyAppAnalyticsProviderId.amplitude].map(\.rawValue)
}

// MARK: - Helpers

private var mirror: (label: String, value: Any?) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import Foundation
import AnalyticsManager
import Foundation

enum KeyAppAnalyticsParameter: AnalyticsParameter {
public enum KeyAppAnalyticsParameter: AnalyticsParameter {
case userHasPositiveBalance(Bool)
case userAggregateBalance(Double)

// Onboarding
case userRestoreMethod(String)
case userDeviceshare(Bool)

case pushAllowed(Bool)
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,23 @@
import Amplitude
import Foundation
import AnalyticsManager
import Foundation

final class AmplitudeAnalyticsProvider: AnalyticsProvider {
var providerId: AnalyticsProviderId {
public final class AmplitudeAnalyticsProvider: AnalyticsProvider {
public var providerId: AnalyticsProviderId {
KeyAppAnalyticsProviderId.amplitude.rawValue
}

init() {
let apiKey: String
#if !RELEASE
apiKey = .secretConfig("AMPLITUDE_API_KEY_FEATURE")!
#else
apiKey = .secretConfig("AMPLITUDE_API_KEY")!
#endif


public init(apiKey: String) {
Amplitude.instance().trackingSessionEvents = true
Amplitude.instance().initializeApiKey(apiKey)
}

func logEvent(_ event: AnalyticsEvent) {
public func logEvent(_ event: AnalyticsEvent) {
guard let eventName = event.name else { return }
Amplitude.instance().logEvent(eventName, withEventProperties: event.params)
}
func logParameter(_ parameter: AnalyticsParameter) {

public func logParameter(_ parameter: AnalyticsParameter) {
guard
let value = parameter.value as? NSObject,
let identify = AMPIdentify().set(parameter.name, value: value)
Expand Down
Loading

0 comments on commit 2b0f6d6

Please sign in to comment.