diff --git a/HackIllinois.xcodeproj/project.pbxproj b/HackIllinois.xcodeproj/project.pbxproj index 1fc4ff37..6302a679 100644 --- a/HackIllinois.xcodeproj/project.pbxproj +++ b/HackIllinois.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 0A360882203539FF001F5F85 /* HIAdminEventViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A360881203539FF001F5F85 /* HIAdminEventViewController.swift */; }; 35240BD1201408DB00E0C0D8 /* HICountdownViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35240BD0201408DB00E0C0D8 /* HICountdownViewController.swift */; }; + 35264667203EC14100F59F48 /* HIRecruiterService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35264666203EC14100F59F48 /* HIRecruiterService.swift */; }; 35BD9E4A2017DFED005B6FCE /* HITrackingService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35BD9E492017DFED005B6FCE /* HITrackingService.swift */; }; 35D7CE9720380ACF00654E28 /* Stickers.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 35D7CE9620380ACF00654E28 /* Stickers.xcassets */; }; 35D7CE9B20380ACF00654E28 /* Stickers.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 35D7CE9420380ACF00654E28 /* Stickers.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; @@ -73,6 +74,8 @@ 95CA9230201E60D300C46037 /* HIImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95CA922F201E60D300C46037 /* HIImage.swift */; }; 95CCEA1F203D6B3600E3E28C /* HINavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95CCEA1E203D6B3600E3E28C /* HINavigationController.swift */; }; 95CD0ED52015217E00D79DCC /* HIApplicationStateController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95CD0ED42015217E00D79DCC /* HIApplicationStateController.swift */; }; + 95D6DA78203F8C3900E7C982 /* HIImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95D6DA77203F8C3900E7C982 /* HIImageView.swift */; }; + 95D6DA7A203F983700E7C982 /* HILocalNotificationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95D6DA79203F983700E7C982 /* HILocalNotificationController.swift */; }; 95D791E9203E12C900C3BA62 /* HIThemeEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95D791E8203E12C900C3BA62 /* HIThemeEngine.swift */; }; 95D791ED203E370A00C3BA62 /* HIWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95D791EC203E370A00C3BA62 /* HIWindow.swift */; }; 95DB8C712018419500173ACC /* HIAPIUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95DB8C702018419500173ACC /* HIAPIUser.swift */; }; @@ -111,6 +114,7 @@ /* Begin PBXFileReference section */ 0A360881203539FF001F5F85 /* HIAdminEventViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HIAdminEventViewController.swift; sourceTree = ""; }; 35240BD0201408DB00E0C0D8 /* HICountdownViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HICountdownViewController.swift; sourceTree = ""; }; + 35264666203EC14100F59F48 /* HIRecruiterService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HIRecruiterService.swift; sourceTree = ""; }; 35BD9E492017DFED005B6FCE /* HITrackingService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HITrackingService.swift; sourceTree = ""; }; 35D7CE9420380ACF00654E28 /* Stickers.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = Stickers.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 35D7CE9620380ACF00654E28 /* Stickers.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Stickers.xcassets; sourceTree = ""; }; @@ -180,6 +184,8 @@ 95CA922F201E60D300C46037 /* HIImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HIImage.swift; sourceTree = ""; }; 95CCEA1E203D6B3600E3E28C /* HINavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HINavigationController.swift; sourceTree = ""; }; 95CD0ED42015217E00D79DCC /* HIApplicationStateController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HIApplicationStateController.swift; sourceTree = ""; }; + 95D6DA77203F8C3900E7C982 /* HIImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HIImageView.swift; sourceTree = ""; }; + 95D6DA79203F983700E7C982 /* HILocalNotificationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HILocalNotificationController.swift; sourceTree = ""; }; 95D791E8203E12C900C3BA62 /* HIThemeEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HIThemeEngine.swift; sourceTree = ""; }; 95D791EC203E370A00C3BA62 /* HIWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HIWindow.swift; sourceTree = ""; }; 95DB8C702018419500173ACC /* HIAPIUser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HIAPIUser.swift; sourceTree = ""; }; @@ -272,13 +278,14 @@ isa = PBXGroup; children = ( 95DE24DB1FC3ADBE000F599D /* HIAnnouncementService.swift */, - 35BD9E492017DFED005B6FCE /* HITrackingService.swift */, 950F57151FBE81FA001F7DF4 /* HIAuthService.swift */, - 84E3DD04203EA27800BF3883 /* HIPassService.swift */, 950F57131FBE8139001F7DF4 /* HIBaseService.swift */, 957D7C831FC28F4100C4332A /* HIEventService.swift */, - 95CA03EF2017F62000CB250F /* HIUserService.swift */, + 84E3DD04203EA27800BF3883 /* HIPassService.swift */, + 35264666203EC14100F59F48 /* HIRecruiterService.swift */, 955772F9202B963800FCE7C0 /* HIRegistrationService.swift */, + 35BD9E492017DFED005B6FCE /* HITrackingService.swift */, + 95CA03EF2017F62000CB250F /* HIUserService.swift */, ); path = APIService; sourceTree = ""; @@ -327,6 +334,7 @@ children = ( 953199C81FC25CA0009F2AA1 /* CoreDataController.swift */, 957DB2E91FC2453100F8C45E /* FlowControllers */, + 95D6DA79203F983700E7C982 /* HILocalNotificationController.swift */, 957DB2E41FC2435100F8C45E /* ViewControllers */, ); path = Controllers; @@ -419,16 +427,17 @@ isa = PBXGroup; children = ( 95069260203EE14000D7C34C /* Animations */, - 95D791E8203E12C900C3BA62 /* HIThemeEngine.swift */, 95A7D27B203D4F54005EAEAF /* HIButton.swift */, 95CA922F201E60D300C46037 /* HIImage.swift */, + 95D6DA77203F8C3900E7C982 /* HIImageView.swift */, 95A7D29D203D5BA4005EAEAF /* HILabel.swift */, 95A7D27C203D4F54005EAEAF /* HISegmentedControl.swift */, 95A7D27D203D4F54005EAEAF /* HITextField.swift */, + 95D791E8203E12C900C3BA62 /* HIThemeEngine.swift */, 95A7D27F203D4F54005EAEAF /* HIView.swift */, + 95D791EC203E370A00C3BA62 /* HIWindow.swift */, 95A7D27E203D4F54005EAEAF /* Identifiable.swift */, 95A7D280203D4F54005EAEAF /* TableView */, - 95D791EC203E370A00C3BA62 /* HIWindow.swift */, ); path = UI; sourceTree = ""; @@ -695,6 +704,7 @@ 9521A6AA20191737009059C6 /* HIAnnouncementDataSource.swift in Sources */, 95C18DCB20096539004784B5 /* HIScheduleViewController.swift in Sources */, 95CCEA1F203D6B3600E3E28C /* HINavigationController.swift in Sources */, + 35264667203EC14100F59F48 /* HIRecruiterService.swift in Sources */, 957D7CAC1FC2940800C4332A /* HackIllinois.xcdatamodeld in Sources */, 9510F6A71FCB7E53007D19DB /* HIScannerViewController.swift in Sources */, 956F41E11FC7577500557DC7 /* HIAnnouncementsViewController.swift in Sources */, @@ -729,7 +739,9 @@ 95A7D28D203D4F54005EAEAF /* Identifiable.swift in Sources */, 9521A6A820191590009059C6 /* HIEventDataSource.swift in Sources */, 9506926E203EE14000D7C34C /* LOTAnimationView.swift in Sources */, + 95D6DA78203F8C3900E7C982 /* HIImageView.swift in Sources */, 95A7D294203D4F54005EAEAF /* HIDateHeader.swift in Sources */, + 95D6DA7A203F983700E7C982 /* HILocalNotificationController.swift in Sources */, 9510F6A31FCB7D6E007D19DB /* Location+CoreDataClass.swift in Sources */, 95D791ED203E370A00C3BA62 /* HIWindow.swift in Sources */, 95A7D29C203D595F005EAEAF /* HITableView.swift in Sources */, diff --git a/HackIllinois/APIService/HIEventService.swift b/HackIllinois/APIService/HIEventService.swift index ea39aae3..890fc46d 100644 --- a/HackIllinois/APIService/HIEventService.swift +++ b/HackIllinois/APIService/HIEventService.swift @@ -15,7 +15,7 @@ final class HIEventService: HIBaseService { return super.baseURL + "/event" } - // MARK: Events + // MARK: - Events static func create(event: HIAPIEvent) -> APIRequest { let eventDict = [String: Any]() return APIRequest(service: self, endpoint: "", body: eventDict, method: .POST) @@ -26,13 +26,30 @@ final class HIEventService: HIBaseService { return APIRequest(service: self, endpoint: "", parameters: paramaters, method: .GET) } - // MARK: Locations - static func create(location: HIAPILocation) -> APIRequest { - let locationDict = [String: Any]() - return APIRequest(service: self, endpoint: "/location", body: locationDict, method: .POST) - } + // MARK: - Locations +// static func create(location: HIAPILocation) -> APIRequest { +// let locationDict = [String: Any]() +// return APIRequest(service: self, endpoint: "/location", body: locationDict, method: .POST) +// } static func getAllLocations() -> APIRequest { return APIRequest(service: self, endpoint: "/location/all", method: .GET) } + + // MARK: - Favorties + static func favortieBy(id: Int) -> APIRequest { + var body = HTTPBody() + body["eventId"] = id + return APIRequest(service: self, endpoint: "/favorite", body: body, method: .POST) + } + + static func unfavortieBy(id: Int) -> APIRequest { + var body = HTTPBody() + body["eventId"] = id + return APIRequest(service: self, endpoint: "/favorite", body: body, method: .DELETE) + } + + static func getAllFavorites() -> APIRequest { + return APIRequest(service: self, endpoint: "/favorite", method: .GET) + } } diff --git a/HackIllinois/APIService/HIPassService.swift b/HackIllinois/APIService/HIPassService.swift index fdb91101..8ff7624e 100644 --- a/HackIllinois/APIService/HIPassService.swift +++ b/HackIllinois/APIService/HIPassService.swift @@ -21,7 +21,6 @@ final class HIPassService: HIBaseService { ] return APIRequest(service: self, endpoint: "", body: params, method: .POST) } - } extension Data: APIReturnable { diff --git a/HackIllinois/APIService/HIRecruiterService.swift b/HackIllinois/APIService/HIRecruiterService.swift new file mode 100644 index 00000000..7f8659cb --- /dev/null +++ b/HackIllinois/APIService/HIRecruiterService.swift @@ -0,0 +1,23 @@ +// +// HIRecruiterService.swift +// HackIllinois +// +// Created by Sujay Patwardhan on 2/22/18. +// Copyright © 2018 HackIllinois. All rights reserved. +// + +import Foundation +import APIManager + +final class HIRecruiterService: HIBaseService { + override static var baseURL: String { + return super.baseURL + "/recruiter" + } + + static func followUserBy(id: Int) -> APIRequest { + var body = HTTPBody() + body["attendeeUserId"] = id + body["favorite"] = true + return APIRequest(service: self, endpoint: "/interest", body: body, method: .POST) + } +} diff --git a/HackIllinois/AppDelegate.swift b/HackIllinois/AppDelegate.swift index 20c5ce22..8c0c0349 100644 --- a/HackIllinois/AppDelegate.swift +++ b/HackIllinois/AppDelegate.swift @@ -9,20 +9,16 @@ import UIKit import SwiftKeychainAccess import CoreLocation +import UserNotifications @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { -// var locationManager = CLLocationManager() - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { setupNavigationBarAppearance() setupTableViewAppearance() _ = HIThemeEngine.shared HIApplicationStateController.shared.initalize() -// locationManager.requestWhenInUseAuthorization() -// locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers -// locationManager.pausesLocationUpdatesAutomatically = true return true } diff --git a/HackIllinois/Assets.xcassets/BackButton.imageset/Contents.json b/HackIllinois/Assets.xcassets/BackButton.imageset/Contents.json index 0ec337e6..6cad6d6b 100644 --- a/HackIllinois/Assets.xcassets/BackButton.imageset/Contents.json +++ b/HackIllinois/Assets.xcassets/BackButton.imageset/Contents.json @@ -19,5 +19,8 @@ "info" : { "version" : 1, "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" } } \ No newline at end of file diff --git a/HackIllinois/Assets.xcassets/DisclosureIndicator.imageset/Contents.json b/HackIllinois/Assets.xcassets/DisclosureIndicator.imageset/Contents.json index 01188e80..542e585e 100644 --- a/HackIllinois/Assets.xcassets/DisclosureIndicator.imageset/Contents.json +++ b/HackIllinois/Assets.xcassets/DisclosureIndicator.imageset/Contents.json @@ -19,5 +19,8 @@ "info" : { "version" : 1, "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" } } \ No newline at end of file diff --git a/HackIllinois/Assets.xcassets/Favorited.imageset/Contents.json b/HackIllinois/Assets.xcassets/Favorited.imageset/Contents.json index c0799b33..b253ca2e 100644 --- a/HackIllinois/Assets.xcassets/Favorited.imageset/Contents.json +++ b/HackIllinois/Assets.xcassets/Favorited.imageset/Contents.json @@ -19,5 +19,8 @@ "info" : { "version" : 1, "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" } } \ No newline at end of file diff --git a/HackIllinois/Assets.xcassets/LogoutButton.imageset/Contents.json b/HackIllinois/Assets.xcassets/LogoutButton.imageset/Contents.json index f089837a..dfc83260 100644 --- a/HackIllinois/Assets.xcassets/LogoutButton.imageset/Contents.json +++ b/HackIllinois/Assets.xcassets/LogoutButton.imageset/Contents.json @@ -19,5 +19,8 @@ "info" : { "version" : 1, "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" } } \ No newline at end of file diff --git a/HackIllinois/Assets.xcassets/MenuClose.imageset/Contents.json b/HackIllinois/Assets.xcassets/MenuClose.imageset/Contents.json index f1234bd9..6d6040e4 100644 --- a/HackIllinois/Assets.xcassets/MenuClose.imageset/Contents.json +++ b/HackIllinois/Assets.xcassets/MenuClose.imageset/Contents.json @@ -19,5 +19,8 @@ "info" : { "version" : 1, "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" } } \ No newline at end of file diff --git a/HackIllinois/Assets.xcassets/MenuFavorited.imageset/Contents.json b/HackIllinois/Assets.xcassets/MenuFavorited.imageset/Contents.json index 4b41dd1d..a497b50d 100644 --- a/HackIllinois/Assets.xcassets/MenuFavorited.imageset/Contents.json +++ b/HackIllinois/Assets.xcassets/MenuFavorited.imageset/Contents.json @@ -19,5 +19,8 @@ "info" : { "version" : 1, "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" } } \ No newline at end of file diff --git a/HackIllinois/Assets.xcassets/MenuOpen.imageset/Contents.json b/HackIllinois/Assets.xcassets/MenuOpen.imageset/Contents.json index 196f3ae8..06a9a652 100644 --- a/HackIllinois/Assets.xcassets/MenuOpen.imageset/Contents.json +++ b/HackIllinois/Assets.xcassets/MenuOpen.imageset/Contents.json @@ -19,5 +19,8 @@ "info" : { "version" : 1, "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" } } \ No newline at end of file diff --git a/HackIllinois/Assets.xcassets/MenuUnfavorited.imageset/Contents.json b/HackIllinois/Assets.xcassets/MenuUnfavorited.imageset/Contents.json index 6a54171c..6d4f05f6 100644 --- a/HackIllinois/Assets.xcassets/MenuUnfavorited.imageset/Contents.json +++ b/HackIllinois/Assets.xcassets/MenuUnfavorited.imageset/Contents.json @@ -19,5 +19,8 @@ "info" : { "version" : 1, "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" } } \ No newline at end of file diff --git a/HackIllinois/Assets.xcassets/Unfavorited.imageset/Contents.json b/HackIllinois/Assets.xcassets/Unfavorited.imageset/Contents.json index 823f9234..f32b4dc7 100644 --- a/HackIllinois/Assets.xcassets/Unfavorited.imageset/Contents.json +++ b/HackIllinois/Assets.xcassets/Unfavorited.imageset/Contents.json @@ -19,5 +19,8 @@ "info" : { "version" : 1, "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" } } \ No newline at end of file diff --git a/HackIllinois/Controllers/FlowControllers/HIApplicationStateController.swift b/HackIllinois/Controllers/FlowControllers/HIApplicationStateController.swift index 5c730812..3d459903 100644 --- a/HackIllinois/Controllers/FlowControllers/HIApplicationStateController.swift +++ b/HackIllinois/Controllers/FlowControllers/HIApplicationStateController.swift @@ -9,6 +9,7 @@ import Foundation import UIKit import SwiftKeychainAccess +import UserNotifications extension Notification.Name { static let loginUser = Notification.Name("HIApplicationStateControllerLoginUser") @@ -58,7 +59,9 @@ extension HIApplicationStateController { func resetPersistentDataIfNeeded() { guard !UserDefaults.standard.bool(forKey: "HIAPPLICATION_INSTALLED") else { return } _ = Keychain.default.purge() + UserDefaults.standard.set(true, forKey: "HIAPPLICATION_INSTALLED") + } func recoverUserIfPossible() { @@ -84,7 +87,7 @@ extension HIApplicationStateController { viewControllers.append(HIAnnouncementsViewController()) viewControllers.append(HIUserDetailViewController()) - if [.volunteer, .staff, .admin].contains(user.permissions) { + if [.volunteer, .mentor, .sponsor, .staff, .admin].contains(user.permissions) { viewControllers.append(HIScannerViewController()) } diff --git a/HackIllinois/Controllers/HILocalNotificationController.swift b/HackIllinois/Controllers/HILocalNotificationController.swift new file mode 100644 index 00000000..61bfc29c --- /dev/null +++ b/HackIllinois/Controllers/HILocalNotificationController.swift @@ -0,0 +1,90 @@ +// +// HILocalNotificationController.swift +// HackIllinois +// +// Created by Rauhul Varma on 2/22/18. +// Copyright © 2018 HackIllinois. All rights reserved. +// + +import Foundation +import UserNotifications + +class HILocalNotificationController: NSObject { + static let shared = HILocalNotificationController() + + private override init() { + super.init() + UNUserNotificationCenter.current().delegate = self + } + + func requestAuthorization(authorized: @escaping (() -> Void)) { + UNUserNotificationCenter.current().getNotificationSettings { (settings) in + switch settings.authorizationStatus { + case .authorized: authorized() + case .denied: break + case .notDetermined: + UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { (granted, _) in + if granted { authorized() } + } + } + } + } + + func scheduleNotifications(for events: [Event]) { + UNUserNotificationCenter.current().removeAllPendingNotificationRequests() + let favoritedEvents = events.filter { $0.favorite } + + for event in favoritedEvents { + scheduleNotification(for: event) + } + } + + func scheduleNotification(for event: Event) { + requestAuthorization { + let scheduleDelay: TimeInterval = 10 + let secondsPerMinute: TimeInterval = 60 + let timeBeforeEventStartForNotification = scheduleDelay * secondsPerMinute + + let now = Date() + guard event.start > now else { return } + let timeIntervalUntilEventStart = event.start.timeIntervalSince(now) + let triggerDelay = max(1, timeIntervalUntilEventStart - timeBeforeEventStartForNotification) + let trigger = UNTimeIntervalNotificationTrigger(timeInterval: triggerDelay, repeats: false) + + let content = UNMutableNotificationContent() + let minutesUntilEvent = min(10, Int(timeIntervalUntilEventStart/secondsPerMinute)) + if minutesUntilEvent <= 1 { + content.title = "\(event.name) starts now!" + } else { + content.title = "\(event.name) starts in \(minutesUntilEvent) minutes!" + } + content.body = event.info + content.sound = UNNotificationSound.default() + + let request = UNNotificationRequest(identifier: "\(event.id)", content: content, trigger: trigger) + + UNUserNotificationCenter.current().add(request) + } + } + + func unscheduleNotification(for event: Event) { + requestAuthorization { + UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: ["\(event.id)"]) + } + } +} + +extension HILocalNotificationController: UNUserNotificationCenterDelegate { + func userNotificationCenter(_ center: UNUserNotificationCenter, + willPresent notification: UNNotification, + withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { + // Play a sound. + completionHandler([.sound, .alert]) + } + + func userNotificationCenter(_ center: UNUserNotificationCenter, + didReceive response: UNNotificationResponse, + withCompletionHandler completionHandler: @escaping () -> Void) { + completionHandler() + } +} diff --git a/HackIllinois/Controllers/ViewControllers/HIAdminAnnouncementViewController.swift b/HackIllinois/Controllers/ViewControllers/HIAdminAnnouncementViewController.swift index 42782e43..4289d6ae 100644 --- a/HackIllinois/Controllers/ViewControllers/HIAdminAnnouncementViewController.swift +++ b/HackIllinois/Controllers/ViewControllers/HIAdminAnnouncementViewController.swift @@ -40,8 +40,8 @@ extension HIAdminAnnouncementViewController { return } - let message = "Create a new notification with title \"\(title)\" and description \"\(description)\"?" - let confirmAlertController = UIAlertController(title: "Confirm Notification", message: message, preferredStyle: .alert) + let message = "Create a new announcement with title \"\(title)\" and description \"\(description)\"?" + let confirmAlertController = UIAlertController(title: "Confirm Announcement", message: message, preferredStyle: .alert) confirmAlertController.addAction( UIAlertAction(title: "Yes", style: .default) { _ in self.stylizeFor(.currentlyCreatingAnnouncement) @@ -53,7 +53,7 @@ extension HIAdminAnnouncementViewController { self?.stylizeFor(.readyToCreateAnnouncement) self?.titleTextField.text = "" self?.descriptionTextField.text = "" - let alert = UIAlertController(title: "Notification Created", message: nil, preferredStyle: .alert) + let alert = UIAlertController(title: "Announcement Created", message: nil, preferredStyle: .alert) alert.addAction( UIAlertAction(title: "OK", style: .default) { _ in self?.navigationController?.popViewController(animated: true) diff --git a/HackIllinois/Controllers/ViewControllers/HIAnnouncementsViewController.swift b/HackIllinois/Controllers/ViewControllers/HIAnnouncementsViewController.swift index 37dc700f..ff6147c5 100644 --- a/HackIllinois/Controllers/ViewControllers/HIAnnouncementsViewController.swift +++ b/HackIllinois/Controllers/ViewControllers/HIAnnouncementsViewController.swift @@ -91,7 +91,7 @@ extension HIAnnouncementsViewController { extension HIAnnouncementsViewController { @objc dynamic override func setupNavigationItem() { super.setupNavigationItem() - title = "NOTIFICATIONS" + title = "ANNOUNCEMENTS" } } diff --git a/HackIllinois/Controllers/ViewControllers/HIBaseViewController.swift b/HackIllinois/Controllers/ViewControllers/HIBaseViewController.swift index 06a9436e..e5b50b17 100644 --- a/HackIllinois/Controllers/ViewControllers/HIBaseViewController.swift +++ b/HackIllinois/Controllers/ViewControllers/HIBaseViewController.swift @@ -134,8 +134,20 @@ extension HIBaseViewController: NSFetchedResultsControllerDelegate { // } func controllerDidChangeContent(_ controller: NSFetchedResultsController) { -// tableView?.endUpdates() - tableView?.reloadData() + guard let tableView = tableView else { return } + tableView.reloadData() + } + + func animateTableViewReload() { + if let tableView = tableView { + UIView.transition( + with: tableView, + duration: 0.25, + options: .transitionCrossDissolve, + animations: { + tableView.reloadData() + }) + } } } diff --git a/HackIllinois/Controllers/ViewControllers/HIEventViewControllers/HIEventDetailViewController.swift b/HackIllinois/Controllers/ViewControllers/HIEventViewControllers/HIEventDetailViewController.swift index 14533275..d1e20432 100644 --- a/HackIllinois/Controllers/ViewControllers/HIEventViewControllers/HIEventDetailViewController.swift +++ b/HackIllinois/Controllers/ViewControllers/HIEventViewControllers/HIEventDetailViewController.swift @@ -17,13 +17,59 @@ class HIEventDetailViewController: HIBaseViewController { // MARK: Views let titleLabel = HILabel(style: .event) let descriptionLabel = HILabel(style: .description) - let favoritedButton = UIButton() + let favoritedButton = HIButton(style: .iconToggle(activeImage: #imageLiteral(resourceName: "Favorited"), inactiveImage: #imageLiteral(resourceName: "Unfavorited"))) // MARK: Constraints var descriptionLabelHeight = NSLayoutConstraint() var tableViewHeight = NSLayoutConstraint() } +// MARK: - Actions +extension HIEventDetailViewController { + @objc func didSelectFavoriteButton(_ sender: HIButton) { + guard let isFavorite = sender.isActive, let event = event else { return } + + if isFavorite { + HIEventService.unfavortieBy(id: Int(event.id)) + .onCompletion { result in + switch result { + case .success: + DispatchQueue.main.async { + HILocalNotificationController.shared.unscheduleNotification(for: event) + event.favorite = false + sender.setToggle(active: event.favorite) + } + case .cancellation: + break + case .failure(let error): + print(error, error.localizedDescription) + } + } + .authorization(HIApplicationStateController.shared.user) + .perform() + + } else { + HIEventService.favortieBy(id: Int(event.id)) + .onCompletion { result in + switch result { + case .success: + DispatchQueue.main.async { + HILocalNotificationController.shared.scheduleNotification(for: event) + event.favorite = true + sender.setToggle(active: event.favorite) + } + case .cancellation: + break + case .failure(let error): + print(error, error.localizedDescription) + } + } + .authorization(HIApplicationStateController.shared.user) + .perform() + } + } +} + // MARK: - UIViewController extension HIEventDetailViewController { override func loadView() { @@ -45,8 +91,7 @@ extension HIEventDetailViewController { upperContainerView.trailingAnchor.constraint(equalTo: eventDetailContainer.trailingAnchor).isActive = true upperContainerView.heightAnchor.constraint(equalToConstant: 63).isActive = true - favoritedButton.setImage(#imageLiteral(resourceName: "Unfavorited"), for: .normal) - favoritedButton.translatesAutoresizingMaskIntoConstraints = false + favoritedButton.addTarget(self, action: #selector(didSelectFavoriteButton(_:)), for: .touchUpInside) upperContainerView.addSubview(favoritedButton) favoritedButton.topAnchor.constraint(equalTo: upperContainerView.topAnchor).isActive = true favoritedButton.leadingAnchor.constraint(equalTo: upperContainerView.leadingAnchor).isActive = true @@ -90,6 +135,7 @@ extension HIEventDetailViewController { guard let event = event else { return } titleLabel.text = event.name descriptionLabel.text = event.info + favoritedButton.setToggle(active: event.favorite) tableView?.reloadData() view.layoutIfNeeded() let targetSize = CGSize(width: descriptionLabel.frame.width, height: .greatestFiniteMagnitude) diff --git a/HackIllinois/Controllers/ViewControllers/HIEventViewControllers/HIEventListViewController.swift b/HackIllinois/Controllers/ViewControllers/HIEventViewControllers/HIEventListViewController.swift index 072e0071..2b723078 100644 --- a/HackIllinois/Controllers/ViewControllers/HIEventViewControllers/HIEventListViewController.swift +++ b/HackIllinois/Controllers/ViewControllers/HIEventViewControllers/HIEventListViewController.swift @@ -28,6 +28,8 @@ extension HIEventListViewController { let cell = tableView.dequeueReusableCell(withIdentifier: HIEventCell.identifier, for: indexPath) if let cell = cell as? HIEventCell, let event = _fetchedResultsController?.object(at: indexPath) as? Event { cell <- event + cell.delegate = self + cell.indexPath = indexPath } return cell } @@ -56,3 +58,55 @@ extension HIEventListViewController { HIEventDataSource.refresh(completion: endRefreshing) } } + +// MARK: - HIEventCellDelegate +extension HIEventListViewController: HIEventCellDelegate { + func eventCellDidSelectFavoriteButton(_ eventCell: HIEventCell) { + guard let indexPath = eventCell.indexPath, + let isFavorite = eventCell.favoritedButton.isActive, + let event = _fetchedResultsController?.object(at: indexPath) as? Event else { return } + + if isFavorite { + HIEventService.unfavortieBy(id: Int(event.id)) + .onCompletion { result in + switch result { + case .success: + DispatchQueue.main.async { + HILocalNotificationController.shared.unscheduleNotification(for: event) + event.favorite = false +// if eventCell.indexPath == indexPath { +// eventCell.setActive(event.favorite) +// } + } + case .cancellation: + break + case .failure(let error): + print(error, error.localizedDescription) + } + } + .authorization(HIApplicationStateController.shared.user) + .perform() + + } else { + HIEventService.favortieBy(id: Int(event.id)) + .onCompletion { result in + switch result { + case .success: + DispatchQueue.main.async { + HILocalNotificationController.shared.scheduleNotification(for: event) + event.favorite = true +// if eventCell.indexPath == indexPath { +// eventCell.setActive(event.favorite) +// } + } + case .cancellation: + break + case .failure(let error): + print(error, error.localizedDescription) + } + } + .authorization(HIApplicationStateController.shared.user) + .perform() + } + } +} diff --git a/HackIllinois/Controllers/ViewControllers/HIEventViewControllers/HIHomeViewController.swift b/HackIllinois/Controllers/ViewControllers/HIEventViewControllers/HIHomeViewController.swift index 8a469d8a..d7cf3914 100644 --- a/HackIllinois/Controllers/ViewControllers/HIEventViewControllers/HIHomeViewController.swift +++ b/HackIllinois/Controllers/ViewControllers/HIEventViewControllers/HIHomeViewController.swift @@ -140,15 +140,7 @@ extension HIHomeViewController { @objc func refreshPredicate() { try? fetchedResultsController.performFetch() - if let tableView = tableView { - UIView.transition( - with: tableView, - duration: 0.125, - options: .transitionCrossDissolve, - animations: { - tableView.reloadData() - }) - } + animateTableViewReload() } func teardownPredicateRefreshTimer() { diff --git a/HackIllinois/Controllers/ViewControllers/HIEventViewControllers/HIScheduleViewController.swift b/HackIllinois/Controllers/ViewControllers/HIEventViewControllers/HIScheduleViewController.swift index 8490b750..b8c2726f 100644 --- a/HackIllinois/Controllers/ViewControllers/HIEventViewControllers/HIScheduleViewController.swift +++ b/HackIllinois/Controllers/ViewControllers/HIEventViewControllers/HIScheduleViewController.swift @@ -33,6 +33,9 @@ class HIScheduleViewController: HIEventListViewController { return fetchedResultsController }() + var currentTab = 0 + var onlyFavorites = false + let onlyFavoritesPredicate = NSPredicate(format: "favorite == YES" ) var dataStore = [(displayText: String, predicate: NSPredicate)]() // MARK: - Init @@ -60,7 +63,7 @@ class HIScheduleViewController: HIEventListViewController { ) dataStore.append((displayText: "SUNDAY", predicate: sundayPredicate)) - fetchedResultsController.fetchRequest.predicate = fridayPredicate + updatePredicate() } override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { @@ -75,17 +78,35 @@ class HIScheduleViewController: HIEventListViewController { // MARK: - Actions extension HIScheduleViewController { @objc func didSelectTab(_ sender: HISegmentedControl) { - fetchedResultsController.fetchRequest.predicate = dataStore[sender.selectedIndex].predicate - try? fetchedResultsController.performFetch() - if let tableView = tableView { - UIView.transition( - with: tableView, - duration: 0.25, - options: .transitionCrossDissolve, - animations: { - tableView.reloadData() - }) + currentTab = sender.selectedIndex + updatePredicate() + animateReload() + } + + @objc func didSelectFavoritesIcon(_ sender: UIBarButtonItem) { + onlyFavorites = !onlyFavorites + if onlyFavorites { + sender.image = #imageLiteral(resourceName: "MenuFavorited") + } else { + sender.image = #imageLiteral(resourceName: "MenuUnfavorited") } + updatePredicate() + animateReload() + } + + func updatePredicate() { + let currentTabPredicate = dataStore[currentTab].predicate + if onlyFavorites { + let compoundPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [currentTabPredicate, onlyFavoritesPredicate]) + fetchedResultsController.fetchRequest.predicate = compoundPredicate + } else { + fetchedResultsController.fetchRequest.predicate = currentTabPredicate + } + } + + func animateReload() { + try? fetchedResultsController.performFetch() + animateTableViewReload() } } @@ -126,6 +147,7 @@ extension HIScheduleViewController { @objc dynamic override func setupNavigationItem() { super.setupNavigationItem() title = "SCHEDULE" + navigationItem.rightBarButtonItem = UIBarButtonItem(image: #imageLiteral(resourceName: "MenuUnfavorited"), style: .plain, target: self, action: #selector(didSelectFavoritesIcon(_:))) } } diff --git a/HackIllinois/Controllers/ViewControllers/HIScannerViewController.swift b/HackIllinois/Controllers/ViewControllers/HIScannerViewController.swift index 30098459..fec6365b 100644 --- a/HackIllinois/Controllers/ViewControllers/HIScannerViewController.swift +++ b/HackIllinois/Controllers/ViewControllers/HIScannerViewController.swift @@ -132,7 +132,8 @@ extension HIScannerViewController: AVCaptureMetadataOutputObjectsDelegate { } func found(code: String) { - guard let url = URL(string: code), + guard let user = HIApplicationStateController.shared.user, + let url = URL(string: code), url.scheme == "hackillinois", let components = URLComponents(url: url, resolvingAgainstBaseURL: true), let queryItems = components.queryItems, @@ -148,7 +149,51 @@ extension HIScannerViewController: AVCaptureMetadataOutputObjectsDelegate { self.lookingUpUserAlertController = lookingUpUserAlertController present(lookingUpUserAlertController, animated: true, completion: nil) + switch user.permissions { + case .volunteer, .staff, .admin: + trackUserBy(id: id) + case .mentor, .sponsor: + followUserBy(id: id) + default: + break + } + } + + func trackUserBy(id: Int) { HITrackingService.track(id: id) + .onCompletion { (result) in + DispatchQueue.main.async { [weak self] in + guard let strongSelf = self, let alert = strongSelf.lookingUpUserAlertController else { return } + switch result { + case .success(let successContainer): + if let error = successContainer.error { + alert.title = error.title + alert.message = error.message + } else { + alert.title = "Success" + } + case .cancellation: + alert.title = "Cancelled" + alert.message = nil + case .failure(let error): + alert.title = "Unknown Error" + alert.message = error.localizedDescription + } + + alert.addAction( + UIAlertAction(title: "Ok", style: .default) { _ in + strongSelf.respondingToQRCodeFound = true + strongSelf.lookingUpUserAlertController = nil + } + ) + } + } + .authorization(HIApplicationStateController.shared.user) + .perform() + } + + func followUserBy(id: Int) { + HIRecruiterService.followUserBy(id: id) .onCompletion { (result) in DispatchQueue.main.async { [weak self] in guard let strongSelf = self, let alert = strongSelf.lookingUpUserAlertController else { return } @@ -184,4 +229,5 @@ extension HIScannerViewController: AVCaptureMetadataOutputObjectsDelegate { .authorization(HIApplicationStateController.shared.user) .perform() } + } diff --git a/HackIllinois/DataSources/HIEventDataSource.swift b/HackIllinois/DataSources/HIEventDataSource.swift index e676f51c..a1cffb3b 100644 --- a/HackIllinois/DataSources/HIEventDataSource.swift +++ b/HackIllinois/DataSources/HIEventDataSource.swift @@ -25,45 +25,62 @@ final class HIEventDataSource { HIEventService.getAllLocations() .onCompletion { result in - switch result { - case .success(let containedLocations): - + if case let .success(containedLocations) = result { + print("GET::LOCATIONS::SUCCESS") HIEventService.getAllEvents() .onCompletion { result in if case let .success(containedEvents) = result { - DispatchQueue.main.sync { - do { - let ctx = CoreDataController.shared.persistentContainer.viewContext - try? ctx.fetch(locationsFetchRequest).forEach { - ctx.delete($0) - } - try? ctx.fetch(eventsFetchRequest).forEach { - ctx.delete($0) - } - var locations = [Location]() - containedLocations.data.forEach { location in - locations.append( Location(context: ctx, location: location) ) - } + print("GET::EVENTS::SUCCESS") + HIEventService.getAllFavorites() + .onCompletion { result in + if case let .success(containedFavorites) = result { + print("GET::FAVORITES::SUCCESS") + + var updatedEvents = [HIAPIEvent]() containedEvents.data.forEach { event in - let eventLocationIds = event.locations.map { Int16($0.locationId) } - let eventLocations = locations.filter { eventLocationIds.contains($0.id) } - _ = Event(context: ctx, event: event, locations: NSSet(array: eventLocations)) + var event = event + event.favorite = containedFavorites.data.map { $0.eventId }.contains(event.id) + updatedEvents.append(event) } - try ctx.save() - } catch { } + + DispatchQueue.main.sync { + do { + let ctx = CoreDataController.shared.persistentContainer.viewContext + try? ctx.fetch(locationsFetchRequest).forEach { + ctx.delete($0) + } + try? ctx.fetch(eventsFetchRequest).forEach { + ctx.delete($0) + } + var locations = [Location]() + containedLocations.data.forEach { location in + locations.append( Location(context: ctx, location: location) ) + } + var events = [Event]() + updatedEvents.forEach { event in + let eventLocationIds = event.locations.map { Int16($0.locationId) } + let eventLocations = locations.filter { eventLocationIds.contains($0.id) } + events.append( Event(context: ctx, event: event, locations: NSSet(array: eventLocations)) ) + } + HILocalNotificationController.shared.scheduleNotifications(for: events) + + try ctx.save() + } catch { } + } + } + completion?() + isRefreshing = false } + .authorization(HIApplicationStateController.shared.user) + .perform() + } else { + completion?() + isRefreshing = false } - completion?() - isRefreshing = false } .authorization(HIApplicationStateController.shared.user) .perform() - - case .cancellation: - completion?() - isRefreshing = false - case .failure(let error): - print(error) + } else { completion?() isRefreshing = false } diff --git a/HackIllinois/Info.plist b/HackIllinois/Info.plist index ad0d0da2..a7d2f483 100644 --- a/HackIllinois/Info.plist +++ b/HackIllinois/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0.6 + 1.0.7 CFBundleURLTypes diff --git a/HackIllinois/Models/APIModels/HIAPIEvent.swift b/HackIllinois/Models/APIModels/HIAPIEvent.swift index 276962e1..9f7b4511 100644 --- a/HackIllinois/Models/APIModels/HIAPIEvent.swift +++ b/HackIllinois/Models/APIModels/HIAPIEvent.swift @@ -20,6 +20,7 @@ struct HIAPIEvent: Codable { case locations } + var favorite = false var id: Int16 var name: String var info: String @@ -42,3 +43,11 @@ struct HIAPILocation: Codable { var longitude: Double var latitude: Double } + +struct HIAPIFavorite: Codable { + typealias Contained = HIAPIReturnDataContainer + + var id: Int16 + var userId: Int16 + var eventId: Int16 +} diff --git a/HackIllinois/Models/CoreDataModels/Event+CoreDataClass.swift b/HackIllinois/Models/CoreDataModels/Event+CoreDataClass.swift index 43237682..79d374e0 100644 --- a/HackIllinois/Models/CoreDataModels/Event+CoreDataClass.swift +++ b/HackIllinois/Models/CoreDataModels/Event+CoreDataClass.swift @@ -14,6 +14,7 @@ public class Event: NSManagedObject { convenience init(context moc: NSManagedObjectContext, event: HIAPIEvent, locations: NSSet) { guard let entity = NSEntityDescription.entity(forEntityName: "Event", in: moc) else { fatalError() } self.init(entity: entity, insertInto: moc) + favorite = event.favorite end = event.end id = event.id info = event.info diff --git a/HackIllinois/Models/CoreDataModels/Event+CoreDataProperties.swift b/HackIllinois/Models/CoreDataModels/Event+CoreDataProperties.swift index 5d0280dd..0214c6f1 100644 --- a/HackIllinois/Models/CoreDataModels/Event+CoreDataProperties.swift +++ b/HackIllinois/Models/CoreDataModels/Event+CoreDataProperties.swift @@ -16,6 +16,7 @@ extension Event { return NSFetchRequest(entityName: "Event") } + @NSManaged public var favorite: Bool @NSManaged public var end: Date @NSManaged public var id: Int16 @NSManaged public var info: String diff --git a/HackIllinois/Models/CoreDataModels/HackIllinois.xcdatamodeld/HackIllinois.xcdatamodel/contents b/HackIllinois/Models/CoreDataModels/HackIllinois.xcdatamodeld/HackIllinois.xcdatamodel/contents index 2bece70e..a00d2fe7 100644 --- a/HackIllinois/Models/CoreDataModels/HackIllinois.xcdatamodeld/HackIllinois.xcdatamodel/contents +++ b/HackIllinois/Models/CoreDataModels/HackIllinois.xcdatamodeld/HackIllinois.xcdatamodel/contents @@ -13,6 +13,7 @@ + @@ -39,7 +40,7 @@ - + \ No newline at end of file diff --git a/HackIllinois/UI/HIButton.swift b/HackIllinois/UI/HIButton.swift index df8b6ff0..1eb668fb 100644 --- a/HackIllinois/UI/HIButton.swift +++ b/HackIllinois/UI/HIButton.swift @@ -11,30 +11,23 @@ import UIKit class HIButton: UIButton { // MARK: - Types - enum Style: Equatable { + enum Style { case standard(title: String?) case async(title: String?) case menu(title: String?, tag: Int) case icon(image: UIImage) - - var rawValue: Int { - switch self { - case .standard: return 0 - case .async: return 1 - case .menu: return 2 - case .icon: return 3 - } - } - - static func == (lhs: HIButton.Style, rhs: HIButton.Style) -> Bool { - return lhs.rawValue == rhs.rawValue - } + case iconToggle(activeImage: UIImage, inactiveImage: UIImage) } // MARK: - Properties let style: Style var activityIndicator: UIActivityIndicatorView? + // MARK: Icon + private(set) var isActive: Bool? + var activeTemplateImage: UIImage? + var inactiveTemplateImage: UIImage? + // MARK: - Init init(style: Style) { self.style = style @@ -46,6 +39,7 @@ class HIButton: UIButton { addTarget(self, action: #selector(handleTouchUpInside), for: .touchUpInside) translatesAutoresizingMaskIntoConstraints = false + adjustsImageWhenHighlighted = false switch style { case .standard(let title): @@ -74,8 +68,14 @@ class HIButton: UIButton { self.tag = tag case .icon(let image): - let templateImage = image.withRenderingMode(.alwaysTemplate) - setImage(templateImage, for: .normal) + activeTemplateImage = image.withRenderingMode(.alwaysTemplate) + setImage(activeTemplateImage, for: .normal) + + case .iconToggle(let activeImage, let inactiveImage): + activeTemplateImage = activeImage.withRenderingMode(.alwaysTemplate) + inactiveTemplateImage = inactiveImage.withRenderingMode(.alwaysTemplate) + setImage(inactiveTemplateImage, for: .normal) + isActive = false } NotificationCenter.default.addObserver(self, selector: #selector(refreshForThemeChange), name: .themeDidChange, object: nil) @@ -109,6 +109,10 @@ class HIButton: UIButton { case .icon: backgroundColor = HIApplication.Palette.current.background tintColor = HIApplication.Palette.current.accent + + case .iconToggle: + tintColor = HIApplication.Palette.current.actionBackground + } } @@ -130,6 +134,16 @@ class HIButton: UIButton { } } + func setToggle(active: Bool) { + guard case .iconToggle = style else { + fatalError("setAsyncTask(_:) can only be used on an HIButton with Style async.") + } + guard isActive != active else { return } + isActive = active + let newImage = active ? activeTemplateImage : inactiveTemplateImage + setImage(newImage, for: .normal) + } + // MARK: - Touch Animations private var animator: UIViewPropertyAnimator? diff --git a/HackIllinois/UI/HIImageView.swift b/HackIllinois/UI/HIImageView.swift new file mode 100644 index 00000000..1144a95b --- /dev/null +++ b/HackIllinois/UI/HIImageView.swift @@ -0,0 +1,50 @@ +// +// HIImageView.swift +// HackIllinois +// +// Created by Rauhul Varma on 2/22/18. +// Copyright © 2018 HackIllinois. All rights reserved. +// + +import Foundation +import UIKit + +class HIImageView: UIImageView { + // MARK: - Types + enum Style { + case icon(image: UIImage) + } + + // MARK: - Properties + let style: Style + + // MARK: - Init + init(style: Style) { + self.style = style + super.init(frame: .zero) + + translatesAutoresizingMaskIntoConstraints = false + + switch style { + case .icon(let image): + self.image = image.withRenderingMode(.alwaysTemplate) + contentMode = .center + } + + NotificationCenter.default.addObserver(self, selector: #selector(refreshForThemeChange), name: .themeDidChange, object: nil) + refreshForThemeChange() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) should not be used.") + } + + deinit { + NotificationCenter.default.removeObserver(self) + } + + // MARK: - Themeable + @objc func refreshForThemeChange() { + tintColor = HIApplication.Palette.current.accent + } +} diff --git a/HackIllinois/UI/TableView/Cells/HIBubbleCell/HIEventCell.swift b/HackIllinois/UI/TableView/Cells/HIBubbleCell/HIEventCell.swift index d7b3205b..49467951 100644 --- a/HackIllinois/UI/TableView/Cells/HIBubbleCell/HIEventCell.swift +++ b/HackIllinois/UI/TableView/Cells/HIBubbleCell/HIEventCell.swift @@ -9,27 +9,31 @@ import Foundation import UIKit +protocol HIEventCellDelegate: class { + func eventCellDidSelectFavoriteButton(_ eventCell: HIEventCell) +} + class HIEventCell: HIBubbleCell { // MARK: - Properties - var favoritedButton = UIButton() + var favoritedButton = HIButton(style: .iconToggle(activeImage: #imageLiteral(resourceName: "Favorited"), inactiveImage: #imageLiteral(resourceName: "Unfavorited"))) var contentStackView = UIStackView() var contentStackViewHeight = NSLayoutConstraint() + var indexPath: IndexPath? + weak var delegate: HIEventCellDelegate? + // MARK: - Init override init(style: UITableViewCellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) - favoritedButton.setImage(#imageLiteral(resourceName: "Unfavorited"), for: .normal) - favoritedButton.translatesAutoresizingMaskIntoConstraints = false + favoritedButton.addTarget(self, action: #selector(didSelectFavoriteButton(_:)), for: .touchUpInside) bubbleView.addSubview(favoritedButton) favoritedButton.topAnchor.constraint(equalTo: bubbleView.topAnchor).isActive = true favoritedButton.leadingAnchor.constraint(equalTo: bubbleView.leadingAnchor).isActive = true favoritedButton.bottomAnchor.constraint(equalTo: bubbleView.bottomAnchor).isActive = true favoritedButton.widthAnchor.constraint(equalToConstant: 58).isActive = true - let disclosureIndicatorView = UIImageView(image: #imageLiteral(resourceName: "DisclosureIndicator")) - disclosureIndicatorView.contentMode = .center - disclosureIndicatorView.translatesAutoresizingMaskIntoConstraints = false + let disclosureIndicatorView = HIImageView(style: .icon(image: #imageLiteral(resourceName: "DisclosureIndicator"))) bubbleView.addSubview(disclosureIndicatorView) disclosureIndicatorView.topAnchor.constraint(equalTo: bubbleView.topAnchor).isActive = true disclosureIndicatorView.bottomAnchor.constraint(equalTo: bubbleView.bottomAnchor).isActive = true @@ -52,6 +56,13 @@ class HIEventCell: HIBubbleCell { } } +// MARK: - Actions +extension HIEventCell { + @objc func didSelectFavoriteButton(_ sender: HIButton) { + delegate?.eventCellDidSelectFavoriteButton(self) + } +} + // MARK: - Population extension HIEventCell { static func heightForCell(with event: Event) -> CGFloat { @@ -59,6 +70,7 @@ extension HIEventCell { } static func <- (lhs: HIEventCell, rhs: Event) { + lhs.favoritedButton.setToggle(active: rhs.favorite) var contentStackViewHeight: CGFloat = 0 let titleLabel = HILabel(style: .event) titleLabel.text = rhs.name @@ -80,6 +92,7 @@ extension HIEventCell { extension HIEventCell { override func prepareForReuse() { super.prepareForReuse() + favoritedButton.setToggle(active: false) contentStackView.arrangedSubviews.forEach { (view) in contentStackView.removeArrangedSubview(view) view.removeFromSuperview() diff --git a/HackIllinois/UI/TableView/Cells/HIEventDetailLocationCell.swift b/HackIllinois/UI/TableView/Cells/HIEventDetailLocationCell.swift index 26ae5e23..fb4704aa 100644 --- a/HackIllinois/UI/TableView/Cells/HIEventDetailLocationCell.swift +++ b/HackIllinois/UI/TableView/Cells/HIEventDetailLocationCell.swift @@ -61,9 +61,7 @@ class HIEventDetailLocationCell: UITableViewCell { titleLabel.leadingAnchor.constraint(equalTo: blurEffectView.contentView.leadingAnchor, constant: 8).isActive = true titleLabel.bottomAnchor.constraint(equalTo: blurEffectView.contentView.bottomAnchor).isActive = true - let disclosureIndicatorImageView = UIImageView(image: #imageLiteral(resourceName: "DisclosureIndicator")) - disclosureIndicatorImageView.contentMode = .center - disclosureIndicatorImageView.translatesAutoresizingMaskIntoConstraints = false + let disclosureIndicatorImageView = HIImageView(style: .icon(image: #imageLiteral(resourceName: "DisclosureIndicator"))) blurEffectView.contentView.addSubview(disclosureIndicatorImageView) disclosureIndicatorImageView.topAnchor.constraint(equalTo: blurEffectView.contentView.topAnchor).isActive = true disclosureIndicatorImageView.leadingAnchor.constraint(equalTo: titleLabel.trailingAnchor, constant: 8).isActive = true @@ -88,9 +86,9 @@ class HIEventDetailLocationCell: UITableViewCell { contentView.backgroundColor = HIApplication.Palette.current.contentBackground switch HIApplication.Theme.current { case .day: - blurEffectView.effect = UIBlurEffect(style: .light) + blurEffectView.backgroundColor = nil case .night: - blurEffectView.effect = UIBlurEffect(style: .extraLight) + blurEffectView.backgroundColor = HIApplication.Palette.current.contentBackground.withAlphaComponent(0.7) } } } diff --git a/Stickers/Info.plist b/Stickers/Info.plist index 329a0094..27a7af21 100644 --- a/Stickers/Info.plist +++ b/Stickers/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 1.0.6 + 1.0.7 CFBundleVersion 1 NSExtension