Skip to content

Commit cfaabc7

Browse files
committed
Add analytics to favorites screen
1 parent 07aec80 commit cfaabc7

File tree

11 files changed

+483
-1491
lines changed

11 files changed

+483
-1491
lines changed

ForPDA.xcodeproj/project.pbxproj

Lines changed: 161 additions & 1469 deletions
Large diffs are not rendered by default.
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
//
2+
// FavoritesEvent.swift
3+
// AnalyticsClient
4+
//
5+
// Created by Ilia Lubianoi on 20.03.2025.
6+
//
7+
8+
import Foundation
9+
10+
public enum FavoritesEvent: Event {
11+
case onRefresh
12+
case onSceneBecomeActive
13+
case favoriteTapped(Int, String, Int?, Bool)
14+
case unreadTapped(Int)
15+
16+
case sortButtonTapped
17+
case readAllButtonTapped
18+
19+
case setImportant(Int, Bool)
20+
case linkCopied(Int, Bool)
21+
case delete(Int)
22+
23+
case goToEnd(Int)
24+
case notify(Int, String)
25+
case notifyHatUpdate(Int)
26+
27+
case sortDismissed
28+
case sortSaveButtonTapped
29+
case sortCancelButtonTapped
30+
case sortTypeSelected(String)
31+
32+
case loadingStart(Int)
33+
case loadingSuccess
34+
case loadingFailure(any Error)
35+
case startUnreadLoadingIndicator(Int)
36+
case jumpRequestFailed
37+
38+
public var name: String {
39+
return "Favorites " + eventName(for: self).inProperCase
40+
}
41+
42+
public var properties: [String: String]? {
43+
switch self {
44+
case let .favoriteTapped(id, name, postId, isForum):
45+
return [
46+
"id": String(id),
47+
"name": name,
48+
"postId": postId.map { String($0) } ?? "nil",
49+
"isForum": isForum.description
50+
]
51+
52+
case let .unreadTapped(id):
53+
return ["id": String(id)]
54+
55+
case let .setImportant(id, isForum):
56+
return ["id": String(id), "isForum": isForum.description]
57+
58+
case let .linkCopied(id, isForum):
59+
return ["id": String(id), "isForum": isForum.description]
60+
61+
case let .delete(id):
62+
return ["id": String(id)]
63+
64+
case let .goToEnd(id):
65+
return ["id": String(id)]
66+
67+
case let .notify(id, type):
68+
return ["id": String(id), "type": type]
69+
70+
case let .notifyHatUpdate(id):
71+
return ["id": String(id)]
72+
73+
case let .sortTypeSelected(type):
74+
return ["type": type]
75+
76+
case let .loadingStart(offset):
77+
return ["offset": String(offset)]
78+
79+
case let .loadingFailure(error):
80+
return ["error": error.localizedDescription]
81+
82+
case let .startUnreadLoadingIndicator(id):
83+
return ["id": String(id)]
84+
85+
default:
86+
return nil
87+
}
88+
}
89+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//
2+
// FavoritesRootEvent.swift
3+
// AnalyticsClient
4+
//
5+
// Created by Ilia Lubianoi on 20.03.2025.
6+
//
7+
8+
import Foundation
9+
10+
public enum FavoritesRootEvent: Event {
11+
case settingsButtonTapped
12+
case tabChanged(Int)
13+
14+
public var name: String {
15+
return "Favorites Root " + eventName(for: self).inProperCase
16+
}
17+
18+
public var properties: [String: String]? {
19+
switch self {
20+
case let .tabChanged(tab):
21+
return ["tab": String(tab)]
22+
default:
23+
return nil
24+
}
25+
}
26+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//
2+
// FavoriteFeature+Analytics.swift
3+
// ForPDA
4+
//
5+
// Created by Ilia Lubianoi on 20.03.2025.
6+
//
7+
8+
import ComposableArchitecture
9+
import AnalyticsClient
10+
11+
extension FavoritesFeature {
12+
13+
struct Analytics: Reducer {
14+
typealias State = FavoritesFeature.State
15+
typealias Action = FavoritesFeature.Action
16+
17+
@Dependency(\.analyticsClient) var analytics
18+
19+
var body: some Reducer<State, Action> {
20+
Reduce<State, Action> { state, action in
21+
switch action {
22+
case .onAppear:
23+
break
24+
25+
case .onRefresh:
26+
analytics.log(FavoritesEvent.onRefresh)
27+
28+
case .onSceneBecomeActive:
29+
analytics.log(FavoritesEvent.onSceneBecomeActive)
30+
31+
case let .favoriteTapped(id: id, name: name, offset: _, postId: postId, isForum: isForum):
32+
analytics.log(FavoritesEvent.favoriteTapped(id, name, postId, isForum))
33+
34+
case let .unreadTapped(id: id):
35+
analytics.log(FavoritesEvent.unreadTapped(id))
36+
37+
case let .contextOptionMenu(option):
38+
switch option {
39+
case .sort:
40+
analytics.log(FavoritesEvent.sortButtonTapped)
41+
case .markAllAsRead:
42+
analytics.log(FavoritesEvent.readAllButtonTapped)
43+
}
44+
45+
case let .commonContextMenu(option, isForum):
46+
switch option {
47+
case let .setImportant(id, pinned):
48+
analytics.log(FavoritesEvent.setImportant(id, pinned))
49+
case let .copyLink(id):
50+
analytics.log(FavoritesEvent.linkCopied(id, isForum))
51+
case let .delete(id):
52+
analytics.log(FavoritesEvent.delete(id))
53+
}
54+
55+
case let .topicContextMenu(option, id):
56+
switch option {
57+
case .goToEnd:
58+
analytics.log(FavoritesEvent.goToEnd(id))
59+
case let .notify(flag, notify):
60+
analytics.log(FavoritesEvent.notify(id, notify.rawValue))
61+
case let .notifyHatUpdate(flag):
62+
analytics.log(FavoritesEvent.notifyHatUpdate(flag))
63+
}
64+
65+
case .pageNavigation:
66+
break // Handled inside navigation
67+
68+
case .sort(.dismiss):
69+
analytics.log(FavoritesEvent.sortDismissed)
70+
71+
case let .sort(.presented(action)):
72+
switch action {
73+
case .onAppear, .binding:
74+
break
75+
case let .didSelectSortType(type):
76+
analytics.log(FavoritesEvent.sortTypeSelected(type.title))
77+
case .saveButtonTapped:
78+
analytics.log(FavoritesEvent.sortSaveButtonTapped)
79+
case .cancelButtonTapped:
80+
analytics.log(FavoritesEvent.sortCancelButtonTapped)
81+
}
82+
83+
case let ._favoritesResponse(response):
84+
switch response {
85+
case .success:
86+
analytics.log(FavoritesEvent.loadingSuccess)
87+
case let .failure(error):
88+
analytics.log(FavoritesEvent.loadingFailure(error))
89+
}
90+
91+
case let ._loadFavorites(offset: offset):
92+
analytics.log(FavoritesEvent.loadingStart(offset))
93+
94+
case let ._startUnreadLoadingIndicator(id: id):
95+
analytics.log(FavoritesEvent.startUnreadLoadingIndicator(id))
96+
97+
case ._jumpRequestFailed:
98+
analytics.log(FavoritesEvent.jumpRequestFailed)
99+
}
100+
101+
return .none
102+
}
103+
}
104+
}
105+
}

Modules/Sources/FavoritesFeature/FavoritesFeature.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,8 @@ public struct FavoritesFeature: Reducer, Sendable {
285285
.ifLet(\.$sort, action: \.sort) {
286286
SortFeature()
287287
}
288+
289+
Analytics()
288290
}
289291

290292
// MARK: - Shared logic

Modules/Sources/FavoritesFeature/Sort/Models/SortType.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,16 @@ public enum SortType {
1111
case byName
1212
case byDate
1313

14-
public var title: LocalizedStringKey {
14+
public var titleLocalized: LocalizedStringKey {
15+
switch self {
16+
case .byName:
17+
return "By name"
18+
case .byDate:
19+
return "By date"
20+
}
21+
}
22+
23+
public var title: String {
1524
switch self {
1625
case .byName:
1726
return "By name"

Modules/Sources/FavoritesFeature/Sort/SortView.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,19 +53,19 @@ struct SortView: View {
5353
Button {
5454
store.send(.didSelectSortType(.byDate))
5555
} label: {
56-
Text(SortType.byDate.title, bundle: .module)
56+
Text(SortType.byDate.titleLocalized, bundle: .module)
5757
Image(systemSymbol: .calendar)
5858
}
5959

6060
Button {
6161
store.send(.didSelectSortType(.byName))
6262
} label: {
63-
Text(SortType.byName.title, bundle: .module)
63+
Text(SortType.byName.titleLocalized, bundle: .module)
6464
Image(systemSymbol: .person)
6565
}
6666
} label: {
6767
HStack {
68-
Text(store.sortType.title, bundle: .module)
68+
Text(store.sortType.titleLocalized, bundle: .module)
6969
.foregroundStyle(Color(.Labels.primary))
7070
.padding(.leading, 16)
7171

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//
2+
// FavoriteRootFeature+Analytics.swift
3+
// ForPDA
4+
//
5+
// Created by Ilia Lubianoi on 20.03.2025.
6+
//
7+
8+
import ComposableArchitecture
9+
import AnalyticsClient
10+
11+
extension FavoritesRootFeature {
12+
13+
struct Analytics: Reducer {
14+
typealias State = FavoritesRootFeature.State
15+
typealias Action = FavoritesRootFeature.Action
16+
17+
@Dependency(\.analyticsClient) var analytics
18+
19+
var body: some Reducer<State, Action> {
20+
Reduce<State, Action> { state, action in
21+
switch action {
22+
case .view(.settingsButtonTapped):
23+
analytics.log(FavoritesRootEvent.settingsButtonTapped)
24+
case .binding(\.pickerSelection):
25+
analytics.log(FavoritesRootEvent.tabChanged(state.pickerSelection.rawValue))
26+
case .binding, .favorites, .bookmarks, .delegate:
27+
break
28+
}
29+
return .none
30+
}
31+
}
32+
}
33+
}

Modules/Sources/FavoritesRootFeature/FavoritesRootFeature.swift

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,17 @@ public struct FavoritesRootFeature: Reducer {
1414

1515
public init() {}
1616

17+
enum PickerSelection: Int {
18+
case favorites = 1
19+
case bookmarks = 2
20+
}
21+
22+
// MARK: - State
23+
1724
@ObservableState
1825
public struct State: Equatable {
26+
var pickerSelection: PickerSelection = .favorites
27+
1928
var favorites: FavoritesFeature.State
2029
var bookmarks: BookmarksFeature.State
2130

@@ -28,7 +37,11 @@ public struct FavoritesRootFeature: Reducer {
2837
}
2938
}
3039

31-
public enum Action: ViewAction {
40+
// MARK: - Action
41+
42+
public enum Action: BindableAction, ViewAction {
43+
case binding(BindingAction<State>)
44+
3245
case favorites(FavoritesFeature.Action)
3346
case bookmarks(BookmarksFeature.Action)
3447

@@ -43,7 +56,11 @@ public struct FavoritesRootFeature: Reducer {
4356
}
4457
}
4558

59+
// MARK: - Body
60+
4661
public var body: some Reducer<State, Action> {
62+
BindingReducer()
63+
4764
Scope(state: \.favorites, action: \.favorites) {
4865
FavoritesFeature()
4966
}
@@ -54,15 +71,14 @@ public struct FavoritesRootFeature: Reducer {
5471

5572
Reduce<State, Action> { state, action in
5673
switch action {
57-
case .favorites, .bookmarks:
74+
case .favorites, .bookmarks, .delegate, .binding:
5875
return .none
5976

6077
case .view(.settingsButtonTapped):
6178
return .send(.delegate(.openSettings))
62-
63-
case .delegate:
64-
return .none
6579
}
6680
}
81+
82+
Analytics()
6783
}
6884
}

0 commit comments

Comments
 (0)