forked from wikimedia/wikipedia-ios
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ArticleLocationCollectionViewController.swift
230 lines (195 loc) · 9.73 KB
/
ArticleLocationCollectionViewController.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
import UIKit
class ArticleLocationCollectionViewController: ColumnarCollectionViewController, DetailPresentingFromContentGroup {
var articleURLs: [URL] {
didSet {
collectionView.reloadData()
}
}
let dataStore: MWKDataStore
fileprivate let locationManager = WMFLocationManager.fine()
private var feedFunnelContext: FeedFunnelContext?
private var previewedIndexPath: IndexPath?
let contentGroupIDURIString: String?
required init(articleURLs: [URL], dataStore: MWKDataStore, contentGroup: WMFContentGroup?, theme: Theme) {
self.articleURLs = articleURLs
self.dataStore = dataStore
contentGroupIDURIString = contentGroup?.objectID.uriRepresentation().absoluteString
super.init()
self.theme = theme
if contentGroup != nil {
self.feedFunnelContext = FeedFunnelContext(contentGroup)
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) not supported")
}
override func viewDidLoad() {
super.viewDidLoad()
layoutManager.register(ArticleLocationCollectionViewCell.self, forCellWithReuseIdentifier: ArticleLocationCollectionViewCell.identifier, addPlaceholder: true)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
locationManager.delegate = self
if locationManager.isAuthorized() {
locationManager.startMonitoringLocation()
}
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
locationManager.delegate = nil
locationManager.stopMonitoringLocation()
if isMovingFromParent, let context = feedFunnelContext {
FeedFunnel.shared.logFeedCardClosed(for: context, maxViewed: maxViewed)
}
}
func articleURL(at indexPath: IndexPath) -> URL {
return articleURLs[indexPath.item]
}
override func collectionView(_ collectionView: UICollectionView, estimatedHeightForItemAt indexPath: IndexPath, forColumnWidth columnWidth: CGFloat) -> ColumnarCollectionViewLayoutHeightEstimate {
var estimate = ColumnarCollectionViewLayoutHeightEstimate(precalculated: false, height: 150)
guard let placeholderCell = layoutManager.placeholder(forCellWithReuseIdentifier: ArticleLocationCollectionViewCell.identifier) as? ArticleLocationCollectionViewCell else {
return estimate
}
placeholderCell.layoutMargins = layout.itemLayoutMargins
configure(cell: placeholderCell, forItemAt: indexPath, layoutOnly: true)
estimate.height = placeholderCell.sizeThatFits(CGSize(width: columnWidth, height: UIView.noIntrinsicMetric), apply: false).height
estimate.precalculated = true
return estimate
}
override func metrics(with size: CGSize, readableWidth: CGFloat, layoutMargins: UIEdgeInsets) -> ColumnarCollectionViewLayoutMetrics {
return ColumnarCollectionViewLayoutMetrics.tableViewMetrics(with: size, readableWidth: readableWidth, layoutMargins: layoutMargins)
}
// MARK: - CollectionViewFooterDelegate
override func collectionViewFooterButtonWasPressed(_ collectionViewFooter: CollectionViewFooter) {
navigationController?.popViewController(animated: true)
}
// MARK: ArticlePreviewingDelegate
override func shareArticlePreviewActionSelected(with articleController: ArticleViewController, shareActivityController: UIActivityViewController) {
guard let context = feedFunnelContext else {
super.shareArticlePreviewActionSelected(with: articleController, shareActivityController: shareActivityController)
return
}
super.shareArticlePreviewActionSelected(with: articleController, shareActivityController: shareActivityController)
FeedFunnel.shared.logFeedDetailShareTapped(for: context, index: previewedIndexPath?.item, midnightUTCDate: context.midnightUTCDate)
}
override func readMoreArticlePreviewActionSelected(with articleController: ArticleViewController) {
guard let context = feedFunnelContext else {
super.readMoreArticlePreviewActionSelected(with: articleController)
return
}
articleController.wmf_removePeekableChildViewControllers()
push(articleController, context: context, index: previewedIndexPath?.item, animated: true)
}
override func saveArticlePreviewActionSelected(with articleController: ArticleViewController, didSave: Bool, articleURL: URL) {
guard let context = feedFunnelContext else {
super.saveArticlePreviewActionSelected(with: articleController, didSave: didSave, articleURL: articleURL)
return
}
if didSave {
ReadingListsFunnel.shared.logSaveInFeed(context: context, articleURL: articleURL, index: previewedIndexPath?.item)
} else {
ReadingListsFunnel.shared.logUnsaveInFeed(context: context, articleURL: articleURL, index: previewedIndexPath?.item)
}
}
func updateLocationOnVisibleCells() {
for cell in collectionView.visibleCells {
guard let locationCell = cell as? ArticleLocationCollectionViewCell else {
continue
}
locationCell.update(userLocation: locationManager.location, heading: locationManager.heading)
}
}
}
// MARK: - UICollectionViewDataSource
extension ArticleLocationCollectionViewController {
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
var numberOfItems: Int {
return articleURLs.count
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return numberOfItems
}
private func configure(cell: UICollectionViewCell, forItemAt indexPath: IndexPath, layoutOnly: Bool) {
guard let cell = cell as? ArticleLocationCollectionViewCell else {
return
}
let url = articleURL(at: indexPath)
guard let article = dataStore.fetchArticle(with: url) else {
return
}
var userLocation: CLLocation?
var userHeading: CLHeading?
if locationManager.isUpdating {
userLocation = locationManager.location
userHeading = locationManager.heading
}
cell.articleLocation = article.location
cell.update(userLocation: userLocation, heading: userHeading)
cell.configure(article: article, displayType: .pageWithLocation, index: indexPath.row, theme: theme, layoutOnly: layoutOnly)
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ArticleLocationCollectionViewCell.identifier, for: indexPath)
configure(cell: cell, forItemAt: indexPath, layoutOnly: false)
return cell
}
}
// MARK: - WMFLocationManagerDelegate
extension ArticleLocationCollectionViewController: WMFLocationManagerDelegate {
func locationManager(_ controller: WMFLocationManager, didUpdate location: CLLocation) {
updateLocationOnVisibleCells()
}
func locationManager(_ controller: WMFLocationManager, didUpdate heading: CLHeading) {
updateLocationOnVisibleCells()
}
func locationManager(_ controller: WMFLocationManager, didChangeEnabledState enabled: Bool) {
if enabled {
locationManager.startMonitoringLocation()
}
}
}
// MARK: - UICollectionViewDelegate
extension ArticleLocationCollectionViewController {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let context = feedFunnelContext {
FeedFunnel.shared.logArticleInFeedDetailReadingStarted(for: context, index: indexPath.item, maxViewed: maxViewed)
}
navigate(to: articleURLs[indexPath.item])
}
}
// MARK: - UIViewControllerPreviewingDelegate
extension ArticleLocationCollectionViewController {
override func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
guard let indexPath = collectionViewIndexPathForPreviewingContext(previewingContext, location: location) else {
return nil
}
previewedIndexPath = indexPath
let articleURL = self.articleURL(at: indexPath)
guard let articleViewController = ArticleViewController(articleURL: articleURL, dataStore: dataStore, theme: self.theme) else {
return nil
}
articleViewController.articlePreviewingDelegate = self
articleViewController.wmf_addPeekableChildViewController(for: articleURL, dataStore: dataStore, theme: theme)
if let context = feedFunnelContext {
FeedFunnel.shared.logArticleInFeedDetailPreviewed(for: context, index: indexPath.item)
}
return articleViewController
}
override func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
if let context = feedFunnelContext {
FeedFunnel.shared.logArticleInFeedDetailReadingStarted(for: context, index: previewedIndexPath?.item, maxViewed: maxViewed)
}
viewControllerToCommit.wmf_removePeekableChildViewControllers()
push(viewControllerToCommit, animated: true)
}
}
// MARK: - Reading lists event logging
extension ArticleLocationCollectionViewController: EventLoggingEventValuesProviding {
var eventLoggingCategory: EventLoggingCategory {
return .places
}
var eventLoggingLabel: EventLoggingLabel? {
return nil
}
}