|
9 | 9 | import UIKit |
10 | 10 | import TimelineTableViewCell |
11 | 11 | import SwiftMessages |
| 12 | +import UserNotifications |
12 | 13 |
|
13 | | -class ScheduleTableViewController: UITableViewController { |
| 14 | +class ScheduleTableViewController: UITableViewController, UNUserNotificationCenterDelegate { |
14 | 15 |
|
15 | 16 | // MARK: Ivars |
16 | 17 | var scheduleTimer = Timer() |
@@ -89,19 +90,14 @@ class ScheduleTableViewController: UITableViewController { |
89 | 90 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { |
90 | 91 |
|
91 | 92 | let cell = tableView.dequeueReusableCell(withIdentifier: "TimelineTableViewCell", for: indexPath) as! TimelineTableViewCell |
92 | | - |
93 | | - // Grab from our custom config |
94 | | - // Description unused for now |
95 | | -// let (timelinePoint, allColor, title, description, isFavorite, date) |
96 | | - |
97 | 93 | let currentTimelineEvent = timelineEvents[convertIndex(fromIndexPath: indexPath)] |
98 | 94 |
|
99 | 95 | /* |
100 | 96 | Overview of how cells are drawn |
101 | 97 |
|
102 | 98 | ---------------- |
103 | 99 | backColor | |
104 | | - tPoint.color o 12:30 (bold) |
| 100 | + tPoint.color o Title (bold) |
105 | 101 | | |
106 | 102 | frontColor | Description |
107 | 103 | | |
@@ -171,6 +167,8 @@ class ScheduleTableViewController: UITableViewController { |
171 | 167 | } |
172 | 168 |
|
173 | 169 |
|
| 170 | + // MARK: Some helper functions |
| 171 | + |
174 | 172 | // Helper function to get a global index for an event from its local table index |
175 | 173 | // Section > Row: |
176 | 174 | // 0 |
@@ -214,21 +212,86 @@ class ScheduleTableViewController: UITableViewController { |
214 | 212 | } |
215 | 213 |
|
216 | 214 | // Update view |
217 | | - // (FavoriteButton subclass handles this condition) |
| 215 | + // (FavoriteButton subclass handles updating this condition) |
218 | 216 | favButton.isSelected = !favButton.isSelected |
219 | 217 |
|
220 | | - // Update model |
221 | | - // (We handle this condition!) |
| 218 | + // Now, prep the model: |
| 219 | + |
| 220 | + // Get the event at this position |
222 | 221 | let indexPath = IndexPath(row: favButton.row!, section: favButton.section!) |
223 | 222 | let selectedEvent = timelineEvents[convertIndex(fromIndexPath: indexPath)] |
| 223 | + |
| 224 | + // Update model |
224 | 225 | selectedEvent.isFavorite = !selectedEvent.isFavorite |
225 | | - print("user toggled \(selectedEvent.event.title)") |
| 226 | + |
| 227 | + // Manage the list of events |
| 228 | + if selectedEvent.isFavorite { |
| 229 | + scheduleFavoriteNotification(forEvent: selectedEvent) |
| 230 | + print("Scheduled notification for \(selectedEvent.event.title)") |
| 231 | + } else { |
| 232 | + unscheduleFavoriteNotification(forEvent: selectedEvent) |
| 233 | + print("Unscheduled notification for \(selectedEvent.event.title)") |
| 234 | + } |
226 | 235 |
|
227 | 236 | // @TODO: Handle updating favorite with server |
228 | | - // @TODO: Handle notifying users on their favorited events |
229 | 237 | } |
230 | 238 |
|
| 239 | + // MARK: Notifications |
| 240 | + private func scheduleFavoriteNotification(forEvent timelineEvent: TimelineEvent) { |
| 241 | + |
| 242 | + askForNotificationPermissionIfNeeded() |
| 243 | + |
| 244 | + // If this looks complicated, see this StackOverflow answer: |
| 245 | + // https://stackoverflow.com/a/60134234/1431900 |
| 246 | + let now = Date(timeIntervalSinceNow: 0) |
| 247 | + |
| 248 | + // If event has already occured, silently fail. |
| 249 | + if (timelineEvent.event.time < now) { |
| 250 | + return |
| 251 | + } |
| 252 | + |
| 253 | + // Otherwise, let's calculate the time until the next event |
| 254 | + let interval = timelineEvent.event.time.timeIntervalSince(Date(timeIntervalSinceNow: 0)) |
| 255 | + let trigger = UNTimeIntervalNotificationTrigger(timeInterval: interval, repeats: false) |
| 256 | + |
| 257 | + let content = UNMutableNotificationContent() |
| 258 | + content.title = timelineEvent.event.title + " is starting!" |
| 259 | + content.body = timelineEvent.event.description |
| 260 | + content.sound = .default |
| 261 | + let request = UNNotificationRequest(identifier: timelineEvent.event.uuid, content: content, trigger: trigger) |
| 262 | + |
| 263 | + // Add request to local notification center |
| 264 | + UNUserNotificationCenter.current().add(request) { error in |
| 265 | + if error != nil { |
| 266 | + DispatchQueue.main.async { |
| 267 | + MessageHandler.showNotificationRegisterError(withEventTitle: timelineEvent.event.title) |
| 268 | + } |
| 269 | + return |
| 270 | + } |
| 271 | + } |
| 272 | + } |
| 273 | + |
| 274 | + private func unscheduleFavoriteNotification(forEvent timelineEvent: TimelineEvent) { |
| 275 | + let identifier = timelineEvent.event.uuid |
| 276 | + UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [identifier]) |
| 277 | + } |
| 278 | + |
| 279 | + private func askForNotificationPermissionIfNeeded() { |
231 | 280 |
|
| 281 | + UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { (granted, error) in |
| 282 | + |
| 283 | + print("NOTIF ERROR: \(error)") |
| 284 | + if !granted { |
| 285 | + DispatchQueue.main.async { |
| 286 | + MessageHandler.showNotificationDisabledInfo() |
| 287 | + } |
| 288 | + } else { |
| 289 | + DispatchQueue.main.async { |
| 290 | + UIApplication.shared.registerForRemoteNotifications() |
| 291 | + } |
| 292 | + } |
| 293 | + } |
| 294 | + } |
232 | 295 |
|
233 | 296 | // MARK: Section headers and view configuration |
234 | 297 |
|
@@ -298,8 +361,6 @@ class ScheduleTableViewController: UITableViewController { |
298 | 361 |
|
299 | 362 | // Otherwise, go on to configure this current section as "passed" |
300 | 363 | self.timelineEvents.filter({ $0.event.section == sectionIndex }).forEach { timelineEvent in |
301 | | - |
302 | | - print("updated \(timelineEvent)") |
303 | 364 | timelineEvent.allColor = self.backColor |
304 | 365 | } |
305 | 366 |
|
|
0 commit comments