From 9d11814e4904373a07ed78591de120c514d7656b Mon Sep 17 00:00:00 2001 From: Thomas Ricouard Date: Wed, 14 Aug 2024 17:23:10 +0200 Subject: [PATCH] Add TelemetryDeck --- .../xcshareddata/swiftpm/Package.resolved | 9 +++++++++ IceCubesApp/App/Main/IceCubesApp.swift | 2 ++ .../Tabs/Settings/AccountSettingView.swift | 3 ++- .../App/Tabs/Timeline/TimelineTab.swift | 4 +++- PRIVACY.MD | 2 ++ Packages/Env/Package.swift | 2 ++ Packages/Env/Sources/Env/Telemetry.swift | 19 +++++++++++++++++++ .../Timeline/View/TimelineViewModel.swift | 5 ++++- 8 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 Packages/Env/Sources/Env/Telemetry.swift diff --git a/IceCubesApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/IceCubesApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 4a1d13bf1..e42e2b04a 100644 --- a/IceCubesApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/IceCubesApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -117,6 +117,15 @@ "version" : "0.3.0" } }, + { + "identity" : "swiftsdk", + "kind" : "remoteSourceControl", + "location" : "https://github.com/TelemetryDeck/SwiftSDK", + "state" : { + "revision" : "13a26cf125b70d695913eb9bea9f9b9c29da5790", + "version" : "2.3.0" + } + }, { "identity" : "swiftsoup", "kind" : "remoteSourceControl", diff --git a/IceCubesApp/App/Main/IceCubesApp.swift b/IceCubesApp/App/Main/IceCubesApp.swift index cc64b64d8..83cbef7e3 100644 --- a/IceCubesApp/App/Main/IceCubesApp.swift +++ b/IceCubesApp/App/Main/IceCubesApp.swift @@ -87,6 +87,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { try? AVAudioSession.sharedInstance().setCategory(.ambient, options: .mixWithOthers) try? AVAudioSession.sharedInstance().setActive(true) PushNotificationsService.shared.setAccounts(accounts: AppAccountsManager.shared.pushAccounts) + Telemetry.setup() + Telemetry.signal("app.launched") return true } diff --git a/IceCubesApp/App/Tabs/Settings/AccountSettingView.swift b/IceCubesApp/App/Tabs/Settings/AccountSettingView.swift index ecf3d0fc2..d93631a5b 100644 --- a/IceCubesApp/App/Tabs/Settings/AccountSettingView.swift +++ b/IceCubesApp/App/Tabs/Settings/AccountSettingView.swift @@ -85,11 +85,12 @@ struct AccountSettingsView: View { await sub.deleteSubscription() } appAccountsManager.delete(account: appAccount) + Telemetry.signal("account.removed") dismiss() } } } label: { - Text("account.action.logout") + Label("account.action.logout", systemImage: "trash") .frame(maxWidth: .infinity) } } diff --git a/IceCubesApp/App/Tabs/Timeline/TimelineTab.swift b/IceCubesApp/App/Tabs/Timeline/TimelineTab.swift index f4b9852b4..b6989128f 100644 --- a/IceCubesApp/App/Tabs/Timeline/TimelineTab.swift +++ b/IceCubesApp/App/Tabs/Timeline/TimelineTab.swift @@ -218,9 +218,11 @@ struct TimelineTab: View { Button { withAnimation { if let index { - pinnedFilters.remove(at: index) + let timeline = pinnedFilters.remove(at: index) + Telemetry.signal("timeline.pin.removed", parameters: ["timeline" : timeline.rawValue]) } else { pinnedFilters.append(timeline) + Telemetry.signal("timeline.pin.added", parameters: ["timeline" : timeline.rawValue]) } } } label: { diff --git a/PRIVACY.MD b/PRIVACY.MD index 6d2fae3d1..93fa1da80 100644 --- a/PRIVACY.MD +++ b/PRIVACY.MD @@ -1,3 +1,5 @@ IceCubesApp does not collect or process any personal information from its users. The app is used to connect to third-party Mastodon servers that may or may not collect personal information and are not covered by this privacy policy. Each third-party Mastodon server comes equipped with its own privacy policy that can be viewed through the app or through that server's website. When you use the OpenAI feature in the composer, please be aware that your input will be sent to the OpenAI server in order to generate a response. Please refer to the [OpenAI Privacy Policy](https://openai.com/policies/privacy-policy) if you want to know more. Nothing is sent to OpenAI if you don't use this feature. You can also completely disable this button in the app settings. + +Ice Cubes use TelemetryDeck to collect anonymized usage data. This helps us understand how our users are using our app and how we can improve it. TelemetryDeck does not collect any personally identifiable information. You can read more about TelemetryDeck’s [privacy policy](https://telemetrydeck.com/privacy) diff --git a/Packages/Env/Package.swift b/Packages/Env/Package.swift index 8c7b09b42..0ffd5dd6f 100644 --- a/Packages/Env/Package.swift +++ b/Packages/Env/Package.swift @@ -20,6 +20,7 @@ let package = Package( .package(name: "Models", path: "../Models"), .package(name: "Network", path: "../Network"), .package(url: "https://github.com/evgenyneu/keychain-swift", branch: "master"), + .package(url: "https://github.com/TelemetryDeck/SwiftSDK", from: "2.3.0") ], targets: [ .target( @@ -28,6 +29,7 @@ let package = Package( .product(name: "Models", package: "Models"), .product(name: "Network", package: "Network"), .product(name: "KeychainSwift", package: "keychain-swift"), + .product(name: "TelemetryDeck", package: "SwiftSDK") ], swiftSettings: [ .enableExperimentalFeature("StrictConcurrency"), diff --git a/Packages/Env/Sources/Env/Telemetry.swift b/Packages/Env/Sources/Env/Telemetry.swift new file mode 100644 index 000000000..f676d5a2e --- /dev/null +++ b/Packages/Env/Sources/Env/Telemetry.swift @@ -0,0 +1,19 @@ +import TelemetryDeck +import SwiftUI + +@MainActor +public class Telemetry { + static var userId: String? { + CurrentAccount.shared.account?.id + } + + public static func setup() { + let config = TelemetryDeck.Config(appID: "F04175D2-599A-4504-867E-CE870B991EB7") + TelemetryDeck.initialize(config: config) + } + + + public static func signal(_ event: String, parameters: [String: String] = [:]) { + TelemetryDeck.signal(event, parameters: parameters, customUserID: userId) + } +} diff --git a/Packages/Timeline/Sources/Timeline/View/TimelineViewModel.swift b/Packages/Timeline/Sources/Timeline/View/TimelineViewModel.swift index b2f94a114..019bac299 100644 --- a/Packages/Timeline/Sources/Timeline/View/TimelineViewModel.swift +++ b/Packages/Timeline/Sources/Timeline/View/TimelineViewModel.swift @@ -9,7 +9,7 @@ import SwiftUI @Observable class TimelineViewModel { var scrollToIndex: Int? var statusesState: StatusesState = .loading - var timeline: TimelineFilter = .federated { + var timeline: TimelineFilter = .home { willSet { if timeline == .home, newValue != .resume { saveMarker() @@ -21,6 +21,9 @@ import SwiftUI await handleLatestOrResume(oldValue) if oldValue != timeline { + Telemetry.signal("timeline.filter.updated", + parameters: ["timeline": timeline.rawValue]) + await reset() pendingStatusesObserver.pendingStatuses = [] tag = nil