Skip to content

Commit

Permalink
Merge pull request #56 from WalletConnect/pulse-analytics
Browse files Browse the repository at this point in the history
Pulse analytics
  • Loading branch information
llbartekll authored Mar 6, 2024
2 parents 2b377bd + bf286f9 commit 4f2f4ca
Show file tree
Hide file tree
Showing 32 changed files with 542 additions and 43 deletions.
17 changes: 8 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ concurrency:

jobs:
test:
runs-on:
group: apple-silicon
runs-on: macos-latest-xlarge
timeout-minutes: 15
strategy:
fail-fast: false
Expand All @@ -31,13 +30,13 @@ jobs:
shell: bash
run: make unit_tests

- name: Danger
env:
DANGER_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run:
rm -rf xcov_report |
/opt/homebrew/opt/ruby/bin/bundle install |
/opt/homebrew/opt/ruby/bin/bundle exec danger
# - name: Danger
# env:
# DANGER_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# run:
# rm -rf xcov_report |
# /opt/homebrew/opt/ruby/bin/bundle install |
# /opt/homebrew/opt/ruby/bin/bundle exec danger

- name: Publish Test Report
uses: mikepenz/action-junit-report@v3
Expand Down
4 changes: 2 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/WalletConnect/WalletConnectSwiftV2",
"state" : {
"revision" : "031c61bfbd4c4eed4a5cb6790152ce736a4f1fba",
"version" : "1.10.0"
"revision" : "4f93c19f02b5b9ae0a984794cae542b9ca1b7471",
"version" : "1.13.0"
}
}
],
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ let package = Package(
url: "https://github.com/pointfreeco/swift-snapshot-testing",
from: "1.10.0"
),
.package(name: "CoinbaseWalletSDK", url: "https://github.com/coinbase/wallet-mobile-sdk.git", from: "1.0.5"),
.package(name: "CoinbaseWalletSDK", url: "https://github.com/WalletConnect/wallet-mobile-sdk", from: "1.0.0"),
],
targets: [
.target(
Expand Down
14 changes: 7 additions & 7 deletions Sample/Example.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

/* Begin PBXBuildFile section */
23F6FD03919B41DE98CAFCD3 /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = BD206AA550964C49AE94A3CA /* Sentry */; };
84D9CCC02B95C277001EDEE3 /* Starscream in Frameworks */ = {isa = PBXBuildFile; productRef = 84D9CCBF2B95C277001EDEE3 /* Starscream */; };
84D9CCC32B9708E4001EDEE3 /* Starscream in Frameworks */ = {isa = PBXBuildFile; productRef = 84D9CCC22B9708E4001EDEE3 /* Starscream */; };
CF0BCCE52AB0886400A2866C /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF0BCCE42AB0886400A2866C /* ContentView.swift */; };
CF25F3A22B40C7070030B3DC /* Web3Modal in Frameworks */ = {isa = PBXBuildFile; productRef = CF25F3A12B40C7070030B3DC /* Web3Modal */; };
CF25F3A42B40C7070030B3DC /* Web3ModalUI in Frameworks */ = {isa = PBXBuildFile; productRef = CF25F3A32B40C7070030B3DC /* Web3ModalUI */; };
Expand Down Expand Up @@ -44,7 +44,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
84D9CCC02B95C277001EDEE3 /* Starscream in Frameworks */,
84D9CCC32B9708E4001EDEE3 /* Starscream in Frameworks */,
CF3B9AD02ACDBA3A00984D53 /* Web3Modal in Frameworks */,
CFD6A70F2ADE8DE2002B402C /* Atlantis in Frameworks */,
CF25F3A42B40C7070030B3DC /* Web3ModalUI in Frameworks */,
Expand Down Expand Up @@ -132,7 +132,7 @@
BD206AA550964C49AE94A3CA /* Sentry */,
CF25F3A12B40C7070030B3DC /* Web3Modal */,
CF25F3A32B40C7070030B3DC /* Web3ModalUI */,
84D9CCBF2B95C277001EDEE3 /* Starscream */,
84D9CCC22B9708E4001EDEE3 /* Starscream */,
);
productName = Example;
productReference = CFD720742A9CC60600636CAF /* Example.app */;
Expand Down Expand Up @@ -166,7 +166,7 @@
CFD6A70D2ADE8DE2002B402C /* XCRemoteSwiftPackageReference "atlantis" */,
CF25F3A02B40C7070030B3DC /* XCLocalSwiftPackageReference ".." */,
F4A0329B6CFF49E682D3DFE7 /* XCRemoteSwiftPackageReference "sentry-cocoa" */,
84D9CCBE2B95C277001EDEE3 /* XCRemoteSwiftPackageReference "Starscream" */,
84D9CCC12B9708E4001EDEE3 /* XCRemoteSwiftPackageReference "Starscream" */,
);
productRefGroup = CFD720752A9CC60600636CAF /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -472,7 +472,7 @@
/* End XCLocalSwiftPackageReference section */

/* Begin XCRemoteSwiftPackageReference section */
84D9CCBE2B95C277001EDEE3 /* XCRemoteSwiftPackageReference "Starscream" */ = {
84D9CCC12B9708E4001EDEE3 /* XCRemoteSwiftPackageReference "Starscream" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/daltoniam/Starscream";
requirement = {
Expand All @@ -499,9 +499,9 @@
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
84D9CCBF2B95C277001EDEE3 /* Starscream */ = {
84D9CCC22B9708E4001EDEE3 /* Starscream */ = {
isa = XCSwiftPackageProductDependency;
package = 84D9CCBE2B95C277001EDEE3 /* XCRemoteSwiftPackageReference "Starscream" */;
package = 84D9CCC12B9708E4001EDEE3 /* XCRemoteSwiftPackageReference "Starscream" */;
productName = Starscream;
};
BD206AA550964C49AE94A3CA /* Sentry */ = {
Expand Down
28 changes: 28 additions & 0 deletions Sources/Web3Modal/Analytics/AnalyticsEvent.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
enum AnalyticsEvent: Equatable {
case MODAL_LOADED
case MODAL_OPEN(connected: Bool)
case MODAL_CLOSE(connected: Bool)
case CLICK_ALL_WALLETS
case SELECT_WALLET(name: String, platform: Method)
case CLICK_NETWORKS
// case OPEN_ACTIVITY_VIEW //
case SWITCH_NETWORK(network: Chain)
case CONNECT_SUCCESS(method: Method, name: String)
case CONNECT_ERROR(message: String)
case DISCONNECT_SUCCESS
case DISCONNECT_ERROR
case CLICK_WALLET_HELP
case CLICK_NETWORK_HELP
case CLICK_GET_WALLET


enum Method: String {
case qrcode = "qrcode"
case mobile = "mobile"
}

// enum Platform: String {
// case qrcode = "QR"
// case mobile = "mobile"
// }
}
4 changes: 4 additions & 0 deletions Sources/Web3Modal/Analytics/AnalyticsEventMapper.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
protocol AnalyticsEventMapper {
func eventName(for event: AnalyticsEvent) -> String
func parameters(for event: AnalyticsEvent) -> [String: String]
}
3 changes: 3 additions & 0 deletions Sources/Web3Modal/Analytics/AnalyticsProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
protocol AnalyticsProvider {
func track(_ event: AnalyticsEvent)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Foundation

/// A builder resulting in an array of analytics event groups
@resultBuilder enum AnalyticsEventGroupBuilder {
/// Return an array of analytics event groups given a closure containing statements of analytics event groups
static func buildBlock(_ eventGroups: AnalyticsEventGroup...) -> [AnalyticsEventGroup] {
eventGroups
}
}

/// A builder resulting in an array of analytics events
@resultBuilder enum AnalyticsEventBuilder {
/// Return an array of analytics events given a closure containing statements of analytics events.
static func buildBlock(_ events: AnalyticsEvent...) -> [AnalyticsEvent] {
events
}
}
24 changes: 24 additions & 0 deletions Sources/Web3Modal/Analytics/Convenience/AnalyticsEventGroup.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/// A group of analytics events tracked together in response to a common trigger
struct AnalyticsEventGroup {
// MARK: Properties

/// The trigger causing the analytics events to be tracked
let trigger: AnalyticsEventTrigger

/// The events being tracked
let events: [AnalyticsEvent]

// MARK: Initializers

init(_ trigger: AnalyticsEventTrigger, events: [AnalyticsEvent]) {
self.trigger = trigger
self.events = events
}
}

extension AnalyticsEventGroup {
/// Initialize with a trigger and event builder
init(_ trigger: AnalyticsEventTrigger, @AnalyticsEventBuilder events: () -> [AnalyticsEvent]) {
self.init(trigger, events: events())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import SwiftUI

/// A view modifier that tracks analytics events
struct AnalyticsEventTrackingModifier: ViewModifier {

@EnvironmentObject var analyticsService: AnalyticsService

/// The groups of analytics events to track
let groups: [AnalyticsEventGroup]

func body(content: Content) -> some View {
content
.onAppear {
trackAll(in: groups(for: .onAppear))
}
.onDisappear {
trackAll(in: groups(for: .onDisappear))
}
.onTapGesture {
trackAll(in: groups(for: .onTapGesture))
}
}

// MARK: Helpers

/// Returns the group for the given trigger
private func groups(for trigger: AnalyticsEventTrigger) -> [AnalyticsEventGroup] {
groups.filter { $0.trigger == trigger }
}

/// Track all events in the given group
private func trackAll(in group: [AnalyticsEventGroup]) {
groups
.flatMap { $0.events }
.forEach { event in
analyticsService.track(event)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/// A trigger that causes analytics events to be tracked
enum AnalyticsEventTrigger {
case onAppear
case onDisappear
case onTapGesture
}
30 changes: 30 additions & 0 deletions Sources/Web3Modal/Analytics/Convenience/View+Track.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import SwiftUI

extension View {

func track(@AnalyticsEventGroupBuilder _ groups: () -> [AnalyticsEventGroup]) -> some View {
let groups = groups()
let modifier = AnalyticsEventTrackingModifier(groups: groups)
return self.modifier(modifier)
}

func track(_ event: AnalyticsEvent) {
let service: AnalyticsService = Environment(\.analyticsService).wrappedValue
service.track(event)
}

func track(@AnalyticsEventBuilder _ events: () -> [AnalyticsEvent]) {
let service: AnalyticsService = Environment(\.analyticsService).wrappedValue
let events = events()
events.forEach { event in
service.track(event)
}
}

/// Track a group of events in response to the trigger with the provided service.
func track(_ trigger: AnalyticsEventTrigger, @AnalyticsEventBuilder _ events: () -> [AnalyticsEvent]) -> some View {
let eventsArray = events()
let group = AnalyticsEventGroup(trigger, events: eventsArray)
return track { group }
}
}
58 changes: 58 additions & 0 deletions Sources/Web3Modal/Analytics/Private/AnalyticsService.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import Foundation

class AnalyticsService: AnalyticsProvider, ObservableObject {
private(set) static var shared = AnalyticsService(providers: [
// LoggingAnalyticsProvider(),
ClickstreamAnalyticsProvider()
])

private let providers: [AnalyticsProvider]
var method: AnalyticsEvent.Method = .mobile

var isAnalyticsEnabled: Bool {
return UserDefaults.standard.bool(forKey: analyticsEnabledKey)
}

// Key to store the state of analytics
private let analyticsEnabledKey = "com.walletconnect.w3m.analyticsEnabled"

init(providers: [AnalyticsProvider]) {
self.providers = providers
// Set default value for analytics enabled if it's not already set
if UserDefaults.standard.object(forKey: analyticsEnabledKey) == nil {
UserDefaults.standard.set(true, forKey: analyticsEnabledKey)
}
}

func track(_ event: AnalyticsEvent) {
guard isAnalyticsEnabled else { return }

providers.forEach {
$0.track(event)
}
if case .SELECT_WALLET(_, let platform) = event {
self.method = platform
}
}

func disable() {
UserDefaults.standard.set(false, forKey: analyticsEnabledKey)
}

func enable() {
UserDefaults.standard.set(true, forKey: analyticsEnabledKey)
}
}

import SwiftUI

struct AnalyticsServiceKey: EnvironmentKey {
static var defaultValue: AnalyticsService = .shared
}

extension EnvironmentValues {
var analyticsService: AnalyticsService {
get { self[AnalyticsServiceKey.self] }
set { self[AnalyticsServiceKey.self] = newValue }
}
}
Loading

0 comments on commit 4f2f4ca

Please sign in to comment.