@@ -7,7 +7,6 @@ import AppKit
77#endif
88
99// TODO: add automatic sending of session length, first install date, distinct days etc. as default parameters
10- // TODO: persist dinstinct days used count separately
1110
1211final class SessionManager : @unchecked Sendable {
1312 private struct StoredSession : Codable {
@@ -25,7 +24,7 @@ final class SessionManager: @unchecked Sendable {
2524
2625 private static let sessionsKey = " sessions "
2726 private static let firstInstallDateKey = " firstInstallDate "
28- private static let distinctDaysUsedCountKey = " distinctDaysUsedCount "
27+ private static let distinctDaysUsedKey = " distinctDaysUsed "
2928
3029 private static let decoder : JSONDecoder = {
3130 let decoder = JSONDecoder ( )
@@ -66,6 +65,7 @@ final class SessionManager: @unchecked Sendable {
6665 self . sessions = [ ]
6766 }
6867
68+ self . updateDistinctDaysUsed ( )
6969 self . setupAppLifecycleObservers ( )
7070 }
7171
@@ -76,15 +76,15 @@ final class SessionManager: @unchecked Sendable {
7676 // if the sessions are empty, this must be the first start after installing the app
7777 if self . sessions. isEmpty {
7878 // this ensures we only use the date, not the time –> e.g. "2025-01-31"
79- let formattedDate = ISO8601DateFormatter . string ( from: Date ( ) , timeZone: . current, formatOptions: [ . withFullDate] )
79+ let todayFormatted = ISO8601DateFormatter . string ( from: Date ( ) , timeZone: . current, formatOptions: [ . withFullDate] )
8080
8181 TelemetryDeck . internalSignal (
8282 " TelemetryDeck.Acquisition.newInstallDetected " ,
83- parameters: [ " TelemetryDeck.Acquisition.firstSessionDate " : formattedDate ]
83+ parameters: [ " TelemetryDeck.Acquisition.firstSessionDate " : todayFormatted ]
8484 )
8585
8686 self . persistenceQueue. async {
87- TelemetryDeck . customDefaults? . set ( formattedDate , forKey: Self . firstInstallDateKey)
87+ TelemetryDeck . customDefaults? . set ( todayFormatted , forKey: Self . firstInstallDateKey)
8888 }
8989 }
9090
@@ -133,8 +133,9 @@ final class SessionManager: @unchecked Sendable {
133133
134134 // Save changes to UserDefaults without blocking Main thread
135135 self . persistenceQueue. async {
136- guard let updatedSessionData = try ? Self . encoder. encode ( self . sessions) else { return }
137- TelemetryDeck . customDefaults? . set ( updatedSessionData, forKey: Self . sessionsKey)
136+ if let updatedSessionData = try ? Self . encoder. encode ( self . sessions) {
137+ TelemetryDeck . customDefaults? . set ( updatedSessionData, forKey: Self . sessionsKey)
138+ }
138139 }
139140 }
140141
@@ -156,6 +157,28 @@ final class SessionManager: @unchecked Sendable {
156157 )
157158 }
158159
160+ private func updateDistinctDaysUsed( ) {
161+ let todayFormatted = ISO8601DateFormatter . string ( from: Date ( ) , timeZone: . current, formatOptions: [ . withFullDate] )
162+
163+ var distinctDays : [ String ] = [ ]
164+ if
165+ let existinDaysData = TelemetryDeck . customDefaults? . data ( forKey: Self . distinctDaysUsedKey) ,
166+ let existingDays = try ? JSONDecoder ( ) . decode ( [ String ] . self, from: existinDaysData)
167+ {
168+ distinctDays = existingDays
169+ }
170+
171+ if distinctDays. last != todayFormatted {
172+ distinctDays. append ( todayFormatted)
173+
174+ self . persistenceQueue. async {
175+ if let updatedDistinctDaysData = try ? JSONEncoder ( ) . encode ( distinctDays) {
176+ TelemetryDeck . customDefaults? . set ( updatedDistinctDaysData, forKey: Self . distinctDaysUsedKey)
177+ }
178+ }
179+ }
180+ }
181+
159182 private func setupAppLifecycleObservers( ) {
160183 #if canImport(WatchKit)
161184 NotificationCenter . default. addObserver (
0 commit comments