1
1
import UIKit
2
2
import Gridicons
3
3
4
+ // This exists in addition to `SiteStatsInsightsDelegate` because `[StatSection]`
5
+ // can't be represented in an Obj-C protocol.
6
+ protocol StatsInsightsManagementDelegate : AnyObject {
7
+ func userUpdatedActiveInsights( _ insights: [ StatSection ] )
8
+ func insightsManagementDismissed( )
9
+ }
10
+
4
11
class AddInsightTableViewController : UITableViewController {
5
12
6
13
// MARK: - Properties
7
-
14
+ private weak var insightsManagementDelegate : StatsInsightsManagementDelegate ?
8
15
private weak var insightsDelegate : SiteStatsInsightsDelegate ?
9
- private var insightsShown = [ StatSection] ( )
16
+
17
+ /// Stored so that we can check if the user has made any changes.
18
+ private var originalInsightsShown = [ StatSection] ( )
19
+ private var insightsShown = [ StatSection] ( ) {
20
+ didSet {
21
+ updateSaveButton ( )
22
+ }
23
+ }
24
+
10
25
private var selectedStat : StatSection ?
11
26
27
+ private lazy var saveButton = UIBarButtonItem ( barButtonSystemItem: . save, target: self , action: #selector( saveInsights) )
28
+
12
29
private lazy var tableHandler : ImmuTableViewHandler = {
13
30
return ImmuTableViewHandler ( takeOver: self )
14
31
} ( )
@@ -17,17 +34,20 @@ class AddInsightTableViewController: UITableViewController {
17
34
18
35
override init ( style: UITableView . Style ) {
19
36
super. init ( style: style)
20
- navigationItem. title = NSLocalizedString ( " Add New Stats Card " , comment: " Add New Stats Card view title " )
37
+
38
+ navigationItem. title = TextContent . title
21
39
}
22
40
23
41
required init ? ( coder aDecoder: NSCoder ) {
24
42
fatalError ( " init(coder:) has not been implemented " )
25
43
}
26
44
27
- convenience init ( insightsDelegate: SiteStatsInsightsDelegate , insightsShown: [ StatSection ] ) {
45
+ convenience init ( insightsDelegate: SiteStatsInsightsDelegate , insightsManagementDelegate : StatsInsightsManagementDelegate ? = nil , insightsShown: [ StatSection ] ) {
28
46
self . init ( style: . grouped)
29
47
self . insightsDelegate = insightsDelegate
48
+ self . insightsManagementDelegate = insightsManagementDelegate
30
49
self . insightsShown = insightsShown
50
+ self . originalInsightsShown = insightsShown
31
51
}
32
52
33
53
// MARK: - View
@@ -39,19 +59,30 @@ class AddInsightTableViewController: UITableViewController {
39
59
reloadViewModel ( )
40
60
WPStyleGuide . configureColors ( view: view, tableView: tableView)
41
61
WPStyleGuide . configureAutomaticHeightRows ( for: tableView)
42
- tableView. accessibilityIdentifier = " Add Insight Table "
62
+ tableView. accessibilityIdentifier = TextContent . title
63
+
64
+ if FeatureFlag . statsNewAppearance. enabled {
65
+ tableView. isEditing = true
66
+ tableView. allowsSelectionDuringEditing = true
67
+ }
43
68
44
69
navigationItem. leftBarButtonItem = UIBarButtonItem ( image: . gridicon( . cross) , style: . plain, target: self , action: #selector( doneTapped) )
45
70
}
46
71
47
72
override func viewWillDisappear( _ animated: Bool ) {
48
73
super. viewWillDisappear ( animated)
49
74
50
- if selectedStat == nil {
51
- insightsDelegate? . addInsightDismissed ? ( )
75
+ if FeatureFlag . statsNewAppearance. enabled {
76
+ // TODO: Check for any changes, prompt user
77
+ } else {
78
+ if selectedStat == nil {
79
+ insightsDelegate? . addInsightDismissed ? ( )
80
+ }
52
81
}
53
82
}
54
83
84
+ // MARK: TableView Data Source / Delegate Overrides
85
+
55
86
override func tableView( _ tableView: UITableView , heightForHeaderInSection section: Int ) -> CGFloat {
56
87
return 38
57
88
}
@@ -60,9 +91,81 @@ class AddInsightTableViewController: UITableViewController {
60
91
return 0
61
92
}
62
93
94
+ override func tableView( _ tableView: UITableView , canMoveRowAt indexPath: IndexPath ) -> Bool {
95
+ guard FeatureFlag . statsNewAppearance. enabled else {
96
+ return false
97
+ }
98
+
99
+ return isActiveCardsSection ( indexPath. section)
100
+ }
101
+
102
+ override func tableView( _ tableView: UITableView , moveRowAt sourceIndexPath: IndexPath , to destinationIndexPath: IndexPath ) {
103
+ guard FeatureFlag . statsNewAppearance. enabled else {
104
+ return
105
+ }
106
+
107
+ if isActiveCardsSection ( sourceIndexPath. section) && isActiveCardsSection ( destinationIndexPath. section) {
108
+ let item = insightsShown. remove ( at: sourceIndexPath. row)
109
+ insightsShown. insert ( item, at: destinationIndexPath. row)
110
+ reloadViewModel ( )
111
+ }
112
+ }
113
+
114
+ override func tableView( _ tableView: UITableView , canEditRowAt indexPath: IndexPath ) -> Bool {
115
+ guard FeatureFlag . statsNewAppearance. enabled else {
116
+ return false
117
+ }
118
+
119
+ return insightsShown. count > 0 && isActiveCardsSection ( indexPath. section)
120
+ }
121
+
122
+ override func tableView( _ tableView: UITableView , targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath , toProposedIndexPath proposedDestinationIndexPath: IndexPath ) -> IndexPath {
123
+ if isActiveCardsSection ( proposedDestinationIndexPath. section) {
124
+ return proposedDestinationIndexPath
125
+ }
126
+
127
+ return IndexPath ( row: insightsShown. count - 1 , section: 0 )
128
+ }
129
+
130
+ override func tableView( _ tableView: UITableView , shouldIndentWhileEditingRowAt indexPath: IndexPath ) -> Bool {
131
+ return false
132
+ }
133
+
134
+ private func isActiveCardsSection( _ sectionIndex: Int ) -> Bool {
135
+ return sectionIndex == 0
136
+ }
137
+
138
+ // MARK: - Actions
139
+
140
+ private func updateSaveButton( ) {
141
+ guard FeatureFlag . statsNewAppearance. enabled else {
142
+ return
143
+ }
144
+
145
+ if insightsShown != originalInsightsShown {
146
+ navigationItem. rightBarButtonItem = saveButton
147
+ } else {
148
+ navigationItem. rightBarButtonItem = nil
149
+ }
150
+ }
151
+
152
+ @objc func saveInsights( ) {
153
+ insightsManagementDelegate? . userUpdatedActiveInsights ( insightsShown)
154
+
155
+ dismiss ( animated: true , completion: nil )
156
+ }
157
+
63
158
@objc private func doneTapped( ) {
64
159
WPAnalytics . trackEvent ( . statsInsightsManagementDismissed)
65
160
dismiss ( animated: true , completion: nil )
161
+
162
+ // TODO: Prompt user if they have unsaved changes
163
+ }
164
+
165
+ fileprivate enum TextContent {
166
+ static let title = NSLocalizedString ( " stats.insights.management.title " , value: " Manage Stats Cards " , comment: " Title of the Stats Insights Management screen " )
167
+ static let activeCardsHeader = NSLocalizedString ( " stats.insights.management.activeCards " , value: " Active Cards " , comment: " Header title indicating which Stats Insights cards the user currently has set to active. " )
168
+ static let placeholderRowTitle = NSLocalizedString ( " stats.insights.management.selectCardsPrompt " , value: " Select cards from the list below " , comment: " Prompt displayed on the Stats Insights management screen telling the user to tap a row to add it to their list of active cards. " )
66
169
}
67
170
}
68
171
@@ -75,33 +178,84 @@ private extension AddInsightTableViewController {
75
178
}
76
179
77
180
func tableViewModel( ) -> ImmuTable {
78
- return ImmuTable ( sections: [ sectionForCategory ( . general) ,
181
+ return ImmuTable ( sections: [ selectedStatsSection ( ) ,
182
+ sectionForCategory ( . general) ,
79
183
sectionForCategory ( . postsAndPages) ,
80
- sectionForCategory ( . activity) ]
184
+ sectionForCategory ( . activity) ] . compactMap ( { $0 } )
81
185
)
82
186
}
83
187
84
188
// MARK: - Table Sections
85
189
86
- func sectionForCategory( _ category: InsightsCategories ) -> ImmuTableSection {
87
- return ImmuTableSection ( headerText: category. title,
88
- rows: category. insights. map {
89
- let enabled = !insightsShown. contains ( $0)
190
+ func selectedStatsSection( ) -> ImmuTableSection ? {
191
+ guard FeatureFlag . statsNewAppearance. enabled else {
192
+ return nil
193
+ }
194
+
195
+ guard insightsShown. count > 0 else {
196
+ return ImmuTableSection ( headerText: TextContent . activeCardsHeader, rows: [ placeholderRow] )
197
+ }
90
198
199
+ return ImmuTableSection ( headerText: TextContent . activeCardsHeader,
200
+ rows: insightsShown. map {
91
201
return AddInsightStatRow ( title: $0. insightManagementTitle,
92
- enabled: enabled,
93
- action: enabled ? rowActionFor ( $0) : nil ) }
202
+ enabled: true ,
203
+ action: rowActionFor ( $0) ) }
204
+ )
205
+ }
206
+
207
+ func sectionForCategory( _ category: InsightsCategories ) -> ImmuTableSection ? {
208
+ guard FeatureFlag . statsNewAppearance. enabled else {
209
+ return ImmuTableSection ( headerText: category. title,
210
+ rows: category. insights. map {
211
+ let enabled = !insightsShown. contains ( $0)
212
+ return AddInsightStatRow ( title: $0. insightManagementTitle,
213
+ enabled: enabled,
214
+ action: enabled ? rowActionFor ( $0) : nil ) }
215
+ )
216
+ }
217
+
218
+ let rows = category. insights. filter ( { !self . insightsShown. contains ( $0) } )
219
+ guard rows. count > 0 else {
220
+ return nil
221
+ }
222
+
223
+ return ImmuTableSection ( headerText: category. title,
224
+ rows: rows. map {
225
+ return AddInsightStatRow ( title: $0. insightManagementTitle,
226
+ enabled: false ,
227
+ action: rowActionFor ( $0) ) }
94
228
)
95
229
}
96
230
97
231
func rowActionFor( _ statSection: StatSection ) -> ImmuTableAction {
98
232
return { [ unowned self] row in
99
- self . selectedStat = statSection
100
- self . insightsDelegate? . addInsightSelected ? ( statSection)
233
+ if FeatureFlag . statsNewAppearance. enabled {
234
+ toggleRow ( for: statSection)
235
+ } else {
236
+ self . selectedStat = statSection
237
+ self . insightsDelegate? . addInsightSelected ? ( statSection)
238
+
239
+ WPAnalytics . track ( . statsInsightsManagementSaved, properties: [ " types " : [ statSection. title] ] )
240
+ self . dismiss ( animated: true , completion: nil )
241
+ }
242
+ }
243
+ }
101
244
102
- WPAnalytics . track ( . statsInsightsManagementSaved, properties: [ " types " : [ statSection. title] ] )
103
- self . dismiss ( animated: true , completion: nil )
245
+ func toggleRow( for statSection: StatSection ) {
246
+ if let index = insightsShown. firstIndex ( of: statSection) {
247
+ insightsShown. remove ( at: index)
248
+ } else {
249
+ insightsShown. append ( statSection)
104
250
}
251
+
252
+ reloadViewModel ( )
253
+ }
254
+
255
+ var placeholderRow : ImmuTableRow {
256
+ return AddInsightStatRow ( title: TextContent . placeholderRowTitle,
257
+ enabled: false ,
258
+ action: nil )
105
259
}
106
260
107
261
// MARK: - Insights Categories
0 commit comments