FacilitiesListViewController.swift 25.8 KB
Newer Older
1
2
3
4
5
//
//  LocationsListViewController.swift
//  WhatsOpen
//
//  Created by Zach Knox on 4/5/17.
Zach Knox's avatar
Zach Knox committed
6
//  Copyright © 2017 SRCT. Some rights reserved.
7
8
9
//

import UIKit
Zach Knox's avatar
Zach Knox committed
10
import DeckTransition
Zach Knox's avatar
Zach Knox committed
11
import RealmSwift
12

Zach Knox's avatar
Zach Knox committed
13
14
//Realm Model
class FacilitiesModel: Object {
Zach Knox's avatar
Zach Knox committed
15
16
	let facilities = List<Facility>()
	let alerts = List<Alert>()
Zach Knox's avatar
Zach Knox committed
17
18
19
20
21
	@objc dynamic var lastUpdated = Date()
	@objc dynamic let id = 0
}


22
class FacilitiesListViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UIViewControllerPreviewingDelegate, UICollectionViewDelegateFlowLayout {
23

24
25
26
27
	// Tell Realm to use this new configuration object for the default Realm
	let realm = try! Realm(configuration: Realm.Configuration(
		// Set the new schema version. This must be greater than the previously used
		// version (if you've never set a schema version before, the version is 0).
28
29
30
31
32
		schemaVersion: 3,
		// We replace the data stored every 12 hours, do we _really_ need to worry about schema updates?
		// I say nay.
		deleteRealmIfMigrationNeeded: true
	  ))
Zach Knox's avatar
Zach Knox committed
33

Zach Knox's avatar
Zach Knox committed
34
	var facilitiesArray = List<Facility>()
Zach Knox's avatar
Zach Knox committed
35
	var alertsList = List<Alert>()
Zach Knox's avatar
Zach Knox committed
36
37
	
	var currentAlerts = List<Alert>()
38
39
    
    // array of facilities that pass the current filters
Zac Wood's avatar
Zac Wood committed
40
    var filteredFacilities = List<Facility>()
41
42
43
	
	// List which actually pertains to what is shown
	var shownFacilities = List<Facility>()
Zac Wood's avatar
Zac Wood committed
44
    
45
    // passing in nil sets the search controller to be this controller
Zac Wood's avatar
Zac Wood committed
46
47
    let searchController = UISearchController(searchResultsController: nil)

Zach Knox's avatar
Zach Knox committed
48
	var filters = Filters()
49
	
50
51
52
53
	override var preferredStatusBarStyle: UIStatusBarStyle {
		return .default
	}
	
54
55
	@IBOutlet var LeftButton: UIBarButtonItem!
	
56
57
	@IBOutlet var settingsButton: UIBarButtonItem!
	
58
	@IBOutlet var LocationsList: UICollectionView!
Zach Knox's avatar
Zach Knox committed
59

60
	@IBOutlet var LocationsListLayout: UICollectionViewFlowLayout!
61
	
62
	@IBOutlet var favoritesControl: UISegmentedControl!
Zach Knox's avatar
Zach Knox committed
63
64
	var showFavorites = false

65
	@IBOutlet var LastUpdatedLabel: UIBarButtonItem!
66
67
    
    let refreshControl = UIRefreshControl()
Zach Knox's avatar
Zach Knox committed
68

Zach Knox's avatar
Zach Knox committed
69
	@IBAction func favoritesControlChanges(_ sender: Any) {
70
		switch self.favoritesControl.selectedSegmentIndex
Zach Knox's avatar
Zach Knox committed
71
72
73
		{
		case 0:
			showFavorites = false
74
			shownFacilities = filteredFacilities
Zach Knox's avatar
Zach Knox committed
75
		case 1:
76
            showFavorites = true
77
			shownFacilities = filterFacilitiesForFavorites()
Zach Knox's avatar
Zach Knox committed
78
79
		default:
			showFavorites = false
80
			shownFacilities = filteredFacilities
Zach Knox's avatar
Zach Knox committed
81
82
83
		}
		self.LocationsList.reloadData()
	}
84
85
86
87
88
89
90
91
92
93
94
    
    /**
     Get all of the facilities that are favorited.
     
     - returns:
        List of facilities that are favorited
     */
    func filterFacilitiesForFavorites() -> List<Facility> {
        var favoriteFacilites = List<Facility>()
        
        // add the facility to favorites list if it is a favorite
95
        favoriteFacilites = filteredFacilities.filter({ (facility: Facility) -> Bool in
96
97
98
99
100
            return Utilities.isFavoriteFacility(facility)
        })
        
        return favoriteFacilites
    }
Zach Knox's avatar
Zach Knox committed
101

102
	override func viewWillLayoutSubviews() {
103
		//LocationsListLayout.itemSize.width = getCellWidth()
Zach Knox's avatar
Zach Knox committed
104
		LocationsListLayout.invalidateLayout()
105
		LocationsList.reloadData()
Zach Knox's avatar
Zach Knox committed
106
107
	}
	
108
	/*
Zach Knox's avatar
Zach Knox committed
109
	func getCellWidth() -> CGFloat {
110
111
		let windowWidth = self.view.frame.size.width
		
Zach Knox's avatar
Zach Knox committed
112
113
		if(windowWidth < 640) {
			return windowWidth - 20
114
115
		}
		else if(windowWidth >= 640 && windowWidth < 1024) {
Zach Knox's avatar
Zach Knox committed
116
			return (windowWidth / 2) - 15
117
118
		}
		else if(windowWidth >= 1024) {
Zach Knox's avatar
Zach Knox committed
119
			return (windowWidth / 3) - 15
120
121
		}
		
Zach Knox's avatar
Zach Knox committed
122
		return 0
123
	}
124
	*/
Zach Knox's avatar
Zach Knox committed
125

126
	@IBAction func RefreshButton(_ sender: Any) {
Zach Knox's avatar
Zach Knox committed
127
		refresh(sender, forceUpdate: true)
128
		reloadWithFilters()
129
	}
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
	
	func checkFilterState() {
		if(filters.showOpen && filters.showClosed && filters.openFirst && filters.sortBy == SortMethod.alphabetical) {
			for f in filters.onlyFromCategories {
				if(f.value != true) {
					LeftButton.title = "Filter (On)"
					return
				}
			}
			for f in filters.onlyFromLocations {
				if(f.value != true) {
					LeftButton.title = "Filter (On)"
					return
				}
			}
145
146
147
148
149
150
			for f in filters.onlyFromCampuses {
				if(f.value != true) {
					LeftButton.title = "Filter (On)"
					return
				}
			}
Zach Knox's avatar
Zach Knox committed
151
152
153
154
155
156
			for f in filters.showAlerts {
				if(f.value != true) {
					LeftButton.title = "Filter (On)"
					return
				}
			}
157
158
159
160
161
			LeftButton.title = "Filter"
			return
		}
		LeftButton.title = "Filter (On)"
	}
Zach Knox's avatar
Zach Knox committed
162

163
164
	override func viewWillAppear(_ animated: Bool) {
		LastUpdatedLabel.isEnabled = false
165
		checkFilterState()
166
		reloadWithFilters()
167
168
	}
	
Zach Knox's avatar
Zach Knox committed
169
	@objc func tapRecognizer(_ sender: UITapGestureRecognizer) {
Zach Knox's avatar
Zach Knox committed
170
171
172
		
		let tapLocation = sender.location(in: LocationsList)
		let indexPath = LocationsList.indexPathForItem(at: tapLocation)
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
		
		if(indexPath != nil) {
			if(indexPath?.section == 1 || currentAlerts.count == 0) {
				let destination = self.storyboard?.instantiateViewController(withIdentifier: "pulling") as? PullingViewController
				destination?.currentViewController = self.storyboard?.instantiateViewController(withIdentifier: "detailView") as? FacilityDetailViewController
				let tapped = self.LocationsList.cellForItem(at: indexPath!) as! FacilityCollectionViewCell
				(destination?.currentViewController as? FacilityDetailViewController)?.facility = tapped.facility
				self.presentDetailView(destination!)
			}
			else {
				let destination = self.storyboard?.instantiateViewController(withIdentifier: "pulling") as? PullingViewController
				destination?.currentViewController = self.storyboard?.instantiateViewController(withIdentifier: "alertDetail") as? AlertDetailViewController
				let tapped = self.LocationsList.cellForItem(at: indexPath!) as! AlertCollectionViewCell
				(destination?.currentViewController as? AlertDetailViewController)?.alert = tapped.alert
				self.presentDetailView(destination!)
			}
Zach Knox's avatar
Zach Knox committed
189
		}
190

Zach Knox's avatar
Zach Knox committed
191
192
	}
	
193
	func presentDetailView(_ destination: PullingViewController) {
Zach Knox's avatar
Zach Knox committed
194
195
196
		if(self.view.traitCollection.horizontalSizeClass == .regular && self.view.traitCollection.verticalSizeClass == .regular) {
			//do a popover here for the iPad
			//iPads are cool right?
Zach Knox's avatar
Zach Knox committed
197
198
199
200
			destination.modalPresentationStyle = .popover
			let popoverController = destination.popoverPresentationController
			popoverController?.permittedArrowDirections = .any
			popoverController?.sourceView = destination.view
Zac Wood's avatar
Zac Wood committed
201
202
203
204
205
206
207
208
            
            // present the detail view over the search controller if we're searching
            if searchController.isActive {
                searchController.present(destination, animated: true, completion: nil)
            }
            else {
                present(destination, animated: true, completion: nil)
            }
Zach Knox's avatar
Zach Knox committed
209
210
211
212
213
		}
		else {
			let destDelegate = DeckTransitioningDelegate()
			destination.modalPresentationStyle = .custom
			destination.transitioningDelegate = destDelegate
Zac Wood's avatar
Zac Wood committed
214
215
216
217
218
219
220
221
            
            // present the detail view over the search controller if we're searching
            if searchController.isActive {
                searchController.present(destination, animated: true, completion: nil)
            }
            else {
                present(destination, animated: true, completion: nil)
            }
Zach Knox's avatar
Zach Knox committed
222
		}
Zac Wood's avatar
Zac Wood committed
223
224
        
        
Zach Knox's avatar
Zach Knox committed
225
	}
Zac Wood's avatar
Zac Wood committed
226
227
228
229
230
231
232
233
234
    
    func configureSearchController() {
        searchController.searchResultsUpdater = self
        searchController.obscuresBackgroundDuringPresentation = false
        
        // add it to the navigationItem
        navigationItem.searchController = searchController
        navigationItem.hidesSearchBarWhenScrolling = true
    }
Zach Knox's avatar
Zach Knox committed
235
236
	
	override func viewDidLoad() {
237
238
        super.viewDidLoad()
		
239
240
		self.definesPresentationContext = true
		
Zach Knox's avatar
Zach Knox committed
241
		if(traitCollection.forceTouchCapability == .available) {
242
243
			registerForPreviewing(with: self, sourceView: self.LocationsList!)
		}
Zach Knox's avatar
Zach Knox committed
244
245
        
        navigationItem.title = "What's Open"
246
		navigationController?.navigationBar.prefersLargeTitles = true
247
248
		navigationItem.largeTitleDisplayMode = .always
		
Zac Wood's avatar
Zac Wood committed
249
        configureSearchController()
Zach Knox's avatar
Zach Knox committed
250
		
251
		LocationsListLayout.invalidateLayout()
Zach Knox's avatar
Zach Knox committed
252
		
253
254
255
		settingsButton.accessibilityLabel = "Settings"
		LastUpdatedLabel.accessibilityHint = ""
		
256
		LocationsListLayout.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10)
Zach Knox's avatar
Zach Knox committed
257

Zach Knox's avatar
Zach Knox committed
258
		refreshControl.addTarget(self, action: #selector(refresh), for: .valueChanged)
259
		LocationsList.refreshControl = refreshControl
Zach Knox's avatar
Zach Knox committed
260
		LocationsList.alwaysBounceVertical = true
Zach Knox's avatar
Zach Knox committed
261

Zach Knox's avatar
Zach Knox committed
262
		refresh(self, forceUpdate: false)
Zach Knox's avatar
Zach Knox committed
263
		
264
		reloadWithFilters()
Zach Knox's avatar
Zach Knox committed
265
		
266
	}
Zach Knox's avatar
Zach Knox committed
267
	
268
	func reloadWithFilters() {
Zach Knox's avatar
Zach Knox committed
269
270
		
		// Facilities
271
272
273
		filteredFacilities = filters.applyFiltersOnFacilities(facilitiesArray)
		shownFacilities = filteredFacilities
		favoritesControlChanges(self)
Zach Knox's avatar
Zach Knox committed
274
275
276
277
278
279
280
281
		
		// Alerts
		let shown = List<Alert>()
		let formatter = ISO8601DateFormatter()
		formatter.timeZone = TimeZone(identifier: "America/New_York")
		let now = Date()
		for alert in alertsList {
			if now.isGreaterThanDate(dateToCompare: formatter.date(from: alert.startDate)!)  && now.isLessThanDate(dateToCompare: formatter.date(from: alert.endDate)!) {
Zach Knox's avatar
Zach Knox committed
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
				switch alert.urgency {
				case "info":
					if(filters.showAlerts["Informational"])! {
						shown.append(alert)
					}
				case "minor":
					if(filters.showAlerts["Minor Alerts"])! {
						shown.append(alert)
					}
				case "major":
					if(filters.showAlerts["Major Alerts"])! {
						shown.append(alert)
					}
				default:
					shown.append(alert)
				}
Zach Knox's avatar
Zach Knox committed
298
299
300
301
302
			}
		}
		currentAlerts = shown
		
		
303
304
		LocationsList.reloadData()
	}
Zac Wood's avatar
Zac Wood committed
305
306
307
308
309
310
311
312
313
    
    func isSearchBarEmpty() -> Bool {
        return searchController.searchBar.text?.isEmpty ?? true
    }
    
    func isSearching() -> Bool {
        return searchController.isActive && !isSearchBarEmpty()
    }
    
314
315
316
317
318
319
320
321
322
323
    /**
     Filters facilities based on the text inputted into the search controller.
     
     - parameters:
        - searchText: text used to filter the facilities.
     - returns:
        List of filtered facilities. Facilities whose names, buildings, or categories match the search text are included.
     */
    func filterFacilitiesForSearchText(_ searchText: String) -> List<Facility> {
        var filtered: List<Facility>
324
325
		
		/*
326
327
328
329
330
331
332
333
334
335
336
337
338
339
        if showFavorites {
            let favoriteFacilities = filterFacilitiesForFavorites()
            
            if searchText == "" { // if the search text is empty, just return the favorites.
                filtered = favoriteFacilities
            } else {
                filtered = favoriteFacilities.filter({(facility: Facility) -> Bool in
                    let hasName = facility.facilityName.lowercased().contains(searchText.lowercased())
                    let hasBuilding = facility.facilityLocation?.building.lowercased().contains(searchText.lowercased()) ?? false
                    let hasCategory = facility.category?.categoryName.lowercased().contains(searchText.lowercased()) ?? false
                    
                    return hasName || hasBuilding || hasCategory
                })
            }
340

341
        } else {
342
343
344
345
346
347
348
349
350
351
		  */
		if searchText == "" {
			filtered = shownFacilities
			LocationsList.reloadData()
			return shownFacilities
		}
		filtered = filteredFacilities.filter({(facility: Facility) -> Bool in
			let hasName = facility.facilityName.lowercased().contains(searchText.lowercased())
			let hasBuilding = facility.facilityLocation?.building.lowercased().contains(searchText.lowercased()) ?? false
			let hasCategory = facility.category?.categoryName.lowercased().contains(searchText.lowercased()) ?? false
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
			var hasTag = false
			for tag in facility.facilityTags! {
				if hasTag {
					break
				}
				if tag.tag.lowercased().contains(searchText.lowercased()) {
					hasTag = true
				}
			}
			var hasLabel = false
			for label in facility.labels! {
				if hasLabel {
					break
				}
				if label.tag.lowercased().contains(searchText.lowercased()) {
					hasLabel = true
				}
			}
			return hasName || hasBuilding || hasCategory || hasTag
371
		})
372
        
Zac Wood's avatar
Zac Wood committed
373
        LocationsList.reloadData()
374
        return filtered
Zac Wood's avatar
Zac Wood committed
375
    }
Zach Knox's avatar
Zach Knox committed
376
	
377
378
379
380
	/*
	* Reloads data, either calling update() to attempt a download
	* or simply pulling from the realm
	*/
381
	@objc func refresh(_ sender: Any, forceUpdate: Bool = true) {
Zach Knox's avatar
Zach Knox committed
382
		refreshControl.beginRefreshing()
Zach Knox's avatar
Zach Knox committed
383
384
385
386
387
388
389
390
		if(forceUpdate) {
			update(sender);
		}
		else {
			let results = realm.objects(FacilitiesModel.self)
			if results.count > 0 {
				let model = results[0]
				let facilities = model.facilities
Zach Knox's avatar
Zach Knox committed
391
				let alerts = model.alerts
Zach Knox's avatar
Zach Knox committed
392
393
				let lastUpdated = model.lastUpdated
				
394
				if((facilities.isEmpty && alerts.isEmpty) || lastUpdated.isLessThanDate(dateToCompare: Date(timeIntervalSinceNow: -43200.0))) {
Zach Knox's avatar
Zach Knox committed
395
396
397
398
					update(sender)
				}
				else {
					facilitiesArray = facilities
Zach Knox's avatar
Zach Knox committed
399
					alertsList = alerts
Zach Knox's avatar
Zach Knox committed
400
					self.LastUpdatedLabel.title = "Updated: " + self.shortDateFormat(lastUpdated)
Zach Knox's avatar
Zach Knox committed
401
402
403
404
405
406
407
				}
			}
			else {
				update(sender)
			}

		}
Zach Knox's avatar
Zach Knox committed
408
		
409
		
410
411
412
413
414
415
416
		updateFiltersLists()
		
		reloadWithFilters()
		refreshControl.endRefreshing()
	}
	
	func updateFiltersLists() {
417
418
419
420
421
422
423
424
		// Add locations and categories to filters
		for f in facilitiesArray {
			if(!filters.onlyFromCategories.keys.contains((f.category?.categoryName)!)) {
				filters.onlyFromCategories.updateValue(true, forKey: (f.category?.categoryName)!)
			}
			if(!filters.onlyFromLocations.keys.contains((f.facilityLocation?.building)!)) {
				filters.onlyFromLocations.updateValue(true, forKey: (f.facilityLocation?.building)!)
			}
425
426
427
			if(!filters.onlyFromCampuses.keys.contains((f.facilityLocation?.campus)!)) {
				filters.onlyFromCampuses.updateValue(true, forKey: (f.facilityLocation?.campus)!)
			}
428
		}
Zach Knox's avatar
Zach Knox committed
429
	}
Zach Knox's avatar
Zach Knox committed
430
	
431
432
433
434
	/*
	* Attempts to update facilitiesArray from the network
	* and place that new information into Realm
	*/
Zach Knox's avatar
Zach Knox committed
435
	func update(_ sender: Any) {
436
		SRCTNetworkController.performDownload { (facilities) in
Zach Knox's avatar
Zach Knox committed
437
438
439
440
441
442
443
444
445
			if(facilities == nil) {
				DispatchQueue.main.async {
					let results = self.realm.objects(FacilitiesModel.self)
					if results.count > 0 {
						let model = results[0]
						let facilitiesFromDB = model.facilities
						let lastUpdated = model.lastUpdated
						
						self.facilitiesArray = facilitiesFromDB
446
						self.updateFiltersLists()
447
						self.reloadWithFilters()
Zach Knox's avatar
Zach Knox committed
448
449
450
451
						self.LastUpdatedLabel.title = "Updated: " + self.shortDateFormat(lastUpdated)
					}
					else {
						self.facilitiesArray = List<Facility>()
Zach Knox's avatar
Zach Knox committed
452
453
					}
				}
Zach Knox's avatar
Zach Knox committed
454
455
456
457
458
459
460
			}
			else {
				self.facilitiesArray = facilities!
				
				DispatchQueue.main.async {
					let date = Date()
					self.LastUpdatedLabel.title = "Updated: " + self.shortDateFormat(date)
Zach Knox's avatar
Zach Knox committed
461

Zach Knox's avatar
Zach Knox committed
462
463
					let results = self.realm.objects(FacilitiesModel.self)
					if results.count == 0 {
Zach Knox's avatar
Zach Knox committed
464
465
466
467
468
						let model = FacilitiesModel()
						for f in facilities! {
							model.facilities.append(f)
						}
						model.lastUpdated = date
Zach Knox's avatar
Zach Knox committed
469
470
471
472
473
474
475
						try! self.realm.write {
							self.realm.add(model)
						}
					}
					else {
						let fromRealm = results[0]
						try! self.realm.write {
Zach Knox's avatar
Zach Knox committed
476
477
478
479
480
							fromRealm.facilities.removeAll()
							for f in facilities! {
								fromRealm.facilities.append(f)
							}
							fromRealm.lastUpdated = date
Zach Knox's avatar
Zach Knox committed
481
						}
Zach Knox's avatar
Zach Knox committed
482
					}
483
484
					self.updateFiltersLists()
					self.reloadWithFilters()
Zach Knox's avatar
Zach Knox committed
485
				}
Zach Knox's avatar
Zach Knox committed
486
			}
Zach Knox's avatar
Zach Knox committed
487
488
489
490
491
492
493
		}
		SRCTNetworkController.performAlertsDownload { (alerts) in
			if(alerts == nil) {
				DispatchQueue.main.async {
					let results = self.realm.objects(FacilitiesModel.self)
					if results.count > 0 {
						let model = results[0]
Zach Knox's avatar
Zach Knox committed
494
						self.alertsList = model.alerts
Zach Knox's avatar
Zach Knox committed
495
496
497
498
499
500
501
502
503
504
505
506
507
					}
					else {
						self.alertsList = List<Alert>()
					}
				}
			}
			else {
				self.alertsList = alerts!
				
				DispatchQueue.main.async {
					let results = self.realm.objects(FacilitiesModel.self)
					if results.count == 0 {
						try! self.realm.write {
Zach Knox's avatar
Zach Knox committed
508
509
510
511
							let model = FacilitiesModel()
							for a in alerts! {
								model.alerts.append(a)
							}
Zach Knox's avatar
Zach Knox committed
512
513
514
515
516
517
							self.realm.add(model)
						}
					}
					else {
						let fromRealm = results[0]
						try! self.realm.write {
Zach Knox's avatar
Zach Knox committed
518
519
520
521
							fromRealm.alerts.removeAll()
							for a in alerts! {
								fromRealm.alerts.append(a)
							}
Zach Knox's avatar
Zach Knox committed
522
523
						}
					}
524
					self.reloadWithFilters()
Zach Knox's avatar
Zach Knox committed
525
526
				}
			}
527
		}
Zach Knox's avatar
Zach Knox committed
528
	}
Zac Wood's avatar
Zac Wood committed
529
    
530
531
532
533
534
535
536
537
538
	func shortDateFormat(_ date: Date) -> String {
		let dateFormatter = DateFormatter()
		dateFormatter.dateStyle = .short
		dateFormatter.timeStyle = .short

		// US English Locale (en_US)
		dateFormatter.locale = Locale(identifier: "en_US")
		return dateFormatter.string(from: date)
	}
Zach Knox's avatar
Zach Knox committed
539
	
540
541
542
543
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
Zach Knox's avatar
Zach Knox committed
544

545
	func numberOfSections(in collectionView: UICollectionView) -> Int {
Zach Knox's avatar
Zach Knox committed
546
		if currentAlerts.count > 0 {
Zach Knox's avatar
Zach Knox committed
547
548
549
550
551
			return 2
		}
		else {
			return 1
		}
552
	}
Zach Knox's avatar
Zach Knox committed
553

554
	func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
Zach Knox's avatar
Zach Knox committed
555
		if(section == 1 || currentAlerts.count == 0) {
Zach Knox's avatar
Zach Knox committed
556
557
558
559
			return shownFacilities.count
		}
		else {
			// TODO: get current alerts, not just any alerts
Zach Knox's avatar
Zach Knox committed
560
			return currentAlerts.count
Zach Knox's avatar
Zach Knox committed
561
562
		}
		
563
	}
Zach Knox's avatar
Zach Knox committed
564

565
	func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
Zach Knox's avatar
Zach Knox committed
566
		
Zach Knox's avatar
Zach Knox committed
567
		if (indexPath.section == 1 || currentAlerts.count == 0) {
Zach Knox's avatar
Zach Knox committed
568
569
570
571
572
			let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCell", for: indexPath) as! FacilityCollectionViewCell
			/*
			let windowRect = self.view.window!.frame
			let windowWidth = windowRect.size.width
			if(windowWidth <= 320) {
Zach Knox's avatar
Zach Knox committed
573
			cell.frame.size.width = 280
Zach Knox's avatar
Zach Knox committed
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
			}
			*/
			//Get tap of the cell
			cell.tapRecognizer.addTarget(self, action: #selector(FacilitiesListViewController.tapRecognizer(_:)))
			cell.gestureRecognizers = []
			cell.gestureRecognizers?.append(cell.tapRecognizer)
			
			
			let facility: Facility
			//let dataArray: [Facility]
			
			/*
			// if something has been searched for, we want to use the filtered array as the data source
			if isSearching() || showFavorites {
			dataArray = placeOpenFacilitiesFirstInArray(filteredFacilities)
			} else {
			dataArray = placeOpenFacilitiesFirstInArray(facilitiesArray)
			}
			*/
			
			
			
			facility = shownFacilities[indexPath.row]
			
			cell.facility = facility
			
			//set labels
			cell.nameLabel.text = facility.facilityName
			cell.categoryLabel.text = facility.category?.categoryName.uppercased()
			
			cell.openClosedLabel.text = Utilities.openOrClosedUntil(facility)
			
			cell.timeDescriptionLabel.text = facility.facilityLocation?.building
			
			//change appearence based on open state
			let open = Utilities.isOpen(facility: facility)
			if(open == true) {
				//cell.openClosedLabel.text = "Open"
				cell.openClosedLabel.textColor = UIColor.black
				cell.openClosedLabel.backgroundColor = UIColor.white
				//cell.openClosedLabel.backgroundColor = UIColor(red:0.00, green:0.40, blue:0.20, alpha:1.0)
				cell.backgroundColor = UIColor(red:0.00, green:0.40, blue:0.20, alpha:1.0)
			} else {
				//cell.openClosedLabel.text = "Closed"
				cell.openClosedLabel.textColor = UIColor.white
				cell.openClosedLabel.backgroundColor = UIColor.black
				//cell.openClosedLabel.backgroundColor = UIColor.red
Eyad Hasan's avatar
Eyad Hasan committed
621
				cell.backgroundColor = UIColor(red:0.17, green:0.17, blue: 0.17, alpha: 1.0)
Zach Knox's avatar
Zach Knox committed
622
623
624
625
626
627
628
629
630
631
632
				
			}
			
			//Accessibility
			//TODO: FIX THIS
			cell.accessibilityLabel = cell.nameLabel.text! + ", Currently " + cell.openClosedLabel.text! + "." + cell.timeDescriptionLabel.text!
			cell.accessibilityHint = "Double Tap to view details"
			
			
			self.reloadInputViews()
			return cell
Zach Knox's avatar
Zach Knox committed
633
		}
Zach Knox's avatar
Zach Knox committed
634
635
		else {
			// Do Alerts things here
Zach Knox's avatar
Zach Knox committed
636
			let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Alert Cell", for: indexPath) as! AlertCollectionViewCell
637
			cell.viewWidth = self.view.frame.width
638
639
640
641
			cell.alert = currentAlerts[indexPath.row]
			cell.tapRecognizer.addTarget(self, action: #selector(FacilitiesListViewController.tapRecognizer(_:)))
			cell.gestureRecognizers = []
			cell.gestureRecognizers?.append(cell.tapRecognizer)
Zach Knox's avatar
Zach Knox committed
642
			
Zach Knox's avatar
Zach Knox committed
643
644
645
			switch currentAlerts[indexPath.row].urgency {
			case "info":
				cell.imageView.image = #imageLiteral(resourceName: "info")
646
				cell.imageView.accessibilityLabel = "Info"
Zach Knox's avatar
Zach Knox committed
647
648
			case "minor":
				cell.imageView.image = #imageLiteral(resourceName: "minor")
649
				cell.imageView.accessibilityLabel = "Minor Alert"
Zach Knox's avatar
Zach Knox committed
650
651
			case "major":
				cell.imageView.image = #imageLiteral(resourceName: "major")
652
				cell.imageView.accessibilityLabel = "Major Alert"
Zach Knox's avatar
Zach Knox committed
653
654
			case "emergency":
				cell.imageView.image = #imageLiteral(resourceName: "emergency")
655
				cell.imageView.accessibilityLabel = "Emergency Alert"
Zach Knox's avatar
Zach Knox committed
656
657
			default:
				cell.imageView.image = #imageLiteral(resourceName: "major")
658
				cell.imageView.accessibilityLabel = "Alert"
Zach Knox's avatar
Zach Knox committed
659
			}
Zach Knox's avatar
Zach Knox committed
660
			cell.messageLabel.text = currentAlerts[indexPath.row].message
661
662

			
Zach Knox's avatar
Zach Knox committed
663
			return cell
664
		}
Zach Knox's avatar
Zach Knox committed
665

666
	}
667
668
	
	func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
Zach Knox's avatar
Zach Knox committed
669
		if(indexPath.section == 1 || currentAlerts.count == 0) {
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
			let height = LocationsListLayout.itemSize.height
			let width: CGFloat
			
			let windowWidth = self.view.frame.size.width
			
			if(windowWidth < 640) {
				width = windowWidth - 20
			}
			else if(windowWidth >= 640 && windowWidth < 1024) {
				width = (windowWidth / 2) - 15
			}
			else if(windowWidth >= 1024) {
				width = (windowWidth / 3) - 15
			}
			else {
				width = windowWidth - 20
			}
			
			return CGSize(width: width, height: height)
		}
		else {
691
			return CGSize(width: self.view.frame.size.width, height: 43)
692
693
694
695
696
697
698
699
700
701
		}
	}

	func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
		var sectionInsets = LocationsListLayout.sectionInset
		if(section != 1 && alertsList.count != 0) {
			sectionInsets.top = 0
		}
		return sectionInsets
	}
Zach Knox's avatar
Zach Knox committed
702

703
704
	
	//unused
Zach Knox's avatar
Zach Knox committed
705
	func getLocationArray(_ facilitiesArray: List<Facility>) -> [Facility] {
Zach Knox's avatar
Zach Knox committed
706
707
708
709
		if(!showFavorites) {
			return placeOpenFacilitiesFirstInArray(facilitiesArray)
		}
		else {
710
			return placeOpenFacilitiesFirstInArray(filteredFacilities)
Zach Knox's avatar
Zach Knox committed
711
		}
Zach Knox's avatar
Zach Knox committed
712
713


Zach Knox's avatar
Zach Knox committed
714
	}
715
	
716
	//unused
Zac Wood's avatar
Zac Wood committed
717
718
719
	// Returns an array which has the open locations listed first
	// Could be improved in the future because currently this means you're checking
	// open status twice per cell
Zach Knox's avatar
Zach Knox committed
720
	func placeOpenFacilitiesFirstInArray(_ facilitiesArray: List<Facility>) -> [Facility] {
721
722
		var open = [Facility]()
		var closed = [Facility]()
Zach Knox's avatar
Zach Knox committed
723

724
725
726
727
728
729
730
731
732
733
734
		for i in facilitiesArray {
			if(Utilities.isOpen(facility: i)) {
				open.append(i)
			}
			else {
				closed.append(i)
			}
		}
		// Test
		return open + closed
	}
Zach Knox's avatar
Zach Knox committed
735

736
	//unused
737
738
739
	func countForOpenAndClosedFacilities(_ facilitiesArray: Array<Facility>) -> (open: Int, closed: Int) {
		var open = 0
		var closed = 0
Zach Knox's avatar
Zach Knox committed
740

741
742
743
744
745
746
747
748
		for i in facilitiesArray {
			if(Utilities.isOpen(facility: i)) {
				open += 1
			}
			else {
				closed += 1
			}
		}
Zach Knox's avatar
Zach Knox committed
749

750
751
		return (open, closed)
	}
Zach Knox's avatar
Zach Knox committed
752
753


754
755
    // MARK: - Navigation

Zach Knox's avatar
Zach Knox committed
756
    //In a storyboard-based application, you will often want to do a little preparation before navigation
Zach Knox's avatar
Zach Knox committed
757
758
759
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destinationViewController.
        if(segue.identifier == "toDetailView") {
760
761
762
            let destination = segue.destination as! PullingViewController
			var destChild = destination.childViewControllers[0] as! FacilityDetailViewController
			destChild = self.storyboard?.instantiateViewController(withIdentifier: "detailView") as! FacilityDetailViewController
Zach Knox's avatar
Zach Knox committed
763
764
765
            let destDelegate = DeckTransitioningDelegate()
            destination.transitioningDelegate = destDelegate
            let tapped = sender as! FacilityCollectionViewCell //this is probably a bad idea just FYI future me
766
			destChild.facility = tapped.facility
Zach Knox's avatar
Zach Knox committed
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783

            // if we're in the search view, present on its controller
            if searchController.isActive {
                searchController.present(destination, animated: true, completion: nil)
            } else {
                present(destination, animated: true, completion: nil)
            }
        }
        else if(segue.identifier == "toFilters") {
            let destination = segue.destination as! UINavigationController
            let filterView = destination.topViewController as! FiltersTableViewController
			filterView.facilities = self.facilitiesArray
            filterView.filters = self.filters
        }

        // Pass the selected object to the new view controller.
    }
784
	
785
786
787
788
	// MARK: - Peek and Pop
	
	func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
		guard let indexPath = LocationsList?.indexPathForItem(at: location) else { return nil }
789
790
		let cell = LocationsList?.cellForItem(at: indexPath) as! FacilityCollectionViewCell
		guard let detailView = storyboard?.instantiateViewController(withIdentifier: "detailView") as? FacilityDetailViewController else { return nil }
791
792
		
		detailView.facility = cell.facility
Zach Knox's avatar
Zach Knox committed
793

794
795
796
797
		return detailView
	}
	
	func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
Zach Knox's avatar
Zach Knox committed
798
799
800
801
802
		let destDelegate = DeckTransitioningDelegate()
		viewControllerToCommit.modalPresentationStyle = .custom
		viewControllerToCommit.transitioningDelegate = destDelegate
		//If one day 3D touch comes to the iPad, this is no longer good.
		present(viewControllerToCommit, animated: true, completion: nil)
803
804
	}
	
805
}
Zac Wood's avatar
Zac Wood committed
806
807
808
809
810

// by implementing UISearchResultsUpdating, we can use this controller for the search controller
extension FacilitiesListViewController: UISearchResultsUpdating {
    func updateSearchResults(for searchController: UISearchController) {
        let searchText = searchController.searchBar.text ?? ""
Zach Knox's avatar
Zach Knox committed
811
        shownFacilities = filterFacilitiesForSearchText(searchText)
Zac Wood's avatar
Zac Wood committed
812
813
814
    }
}

Zach Knox's avatar
Zach Knox committed
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
// based on https://stackoverflow.com/questions/26198526/nsdate-comparison-using-swift
extension Date {
	func isGreaterThanDate(dateToCompare: Date) -> Bool {
		//Declare Variables
		var isGreater = false
		
		//Compare Values
		if self.compare(dateToCompare) == ComparisonResult.orderedDescending {
			isGreater = true
		}
		
		//Return Result
		return isGreater
	}
	
	func isLessThanDate(dateToCompare: Date) -> Bool {
		//Declare Variables
		var isLess = false
		
		//Compare Values
		if self.compare(dateToCompare) == ComparisonResult.orderedAscending {
			isLess = true
		}
		
		//Return Result
		return isLess
	}
	
	func equalToDate(dateToCompare: Date) -> Bool {
		//Declare Variables
		var isEqualTo = false
		
		//Compare Values
		if self.compare(dateToCompare) == ComparisonResult.orderedSame {
			isEqualTo = true
		}
		
		//Return Result
		return isEqualTo
	}
}

Zach Knox's avatar
Zach Knox committed
857
858