diff --git a/Announcer/Announcement VC/AnnouncementSearchBar.swift b/Announcer/Announcement VC/AnnouncementSearchBar.swift index 28ebcb1..94ec6e1 100644 --- a/Announcer/Announcement VC/AnnouncementSearchBar.swift +++ b/Announcer/Announcement VC/AnnouncementSearchBar.swift @@ -19,6 +19,10 @@ extension AnnouncementsViewController: UISearchBarDelegate { // When text changes, update search results with searchText // Seach results automatically reloads when value changed func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { + // Handling when posts are missing because reloading + if posts == nil { return } + + // It takes a bit to search so just run it in the background DispatchQueue.global(qos: .background).async { // Set color of labels // Update labels/textview with data diff --git a/Announcer/Announcement VC/AnnouncementsViewController.swift b/Announcer/Announcement VC/AnnouncementsViewController.swift index cdd3df3..c396c24 100644 --- a/Announcer/Announcement VC/AnnouncementsViewController.swift +++ b/Announcer/Announcement VC/AnnouncementsViewController.swift @@ -168,17 +168,28 @@ class AnnouncementsViewController: UIViewController { } func addItemsToCoreSpotlight() { + + /// So that it does not crash when `posts` gets forced unwrapped + if posts == nil { + return + } + + /// `posts` converted to `CSSearchableItems` let items: [CSSearchableItem] = posts.map({ post in let attributeSet = CSSearchableItemAttributeSet(itemContentType: kUTTypeText as String) attributeSet.title = post.title attributeSet.contentDescription = post.content.condenseLinebreaks().htmlToString - - return CSSearchableItem(uniqueIdentifier: "\(post.title)", - domainIdentifier: Bundle.main.bundleIdentifier!, - attributeSet: attributeSet) + + let item = CSSearchableItem(uniqueIdentifier: "\(post.title)", domainIdentifier: Bundle.main.bundleIdentifier!, attributeSet: attributeSet) + + item.expirationDate = Date.distantFuture + + return item }) + // Index the items CSSearchableIndex.default().indexSearchableItems(items) { error in + // Make sure there is no error indexing everything if let error = error { print("Indexing error: \(error.localizedDescription)") } else { diff --git a/Announcer/Storyboards/Base.lproj/LaunchScreen.storyboard b/Announcer/Storyboards/Base.lproj/LaunchScreen.storyboard index 5e91fb4..4b9e8c4 100644 --- a/Announcer/Storyboards/Base.lproj/LaunchScreen.storyboard +++ b/Announcer/Storyboards/Base.lproj/LaunchScreen.storyboard @@ -58,7 +58,7 @@ - + @@ -89,11 +89,11 @@ - - - + + + diff --git a/Announcer/Storyboards/Base.lproj/Main.storyboard b/Announcer/Storyboards/Base.lproj/Main.storyboard index 55d48f1..2ec6ffb 100644 --- a/Announcer/Storyboards/Base.lproj/Main.storyboard +++ b/Announcer/Storyboards/Base.lproj/Main.storyboard @@ -37,7 +37,7 @@ - + @@ -72,7 +72,7 @@ - + @@ -138,7 +138,7 @@ - + @@ -199,7 +199,7 @@ - + diff --git a/Announcer/Storyboards/Content.storyboard b/Announcer/Storyboards/Content.storyboard index 4e2747e..441b00e 100644 --- a/Announcer/Storyboards/Content.storyboard +++ b/Announcer/Storyboards/Content.storyboard @@ -349,7 +349,7 @@ - + @@ -414,7 +414,7 @@ - + diff --git a/Announcer/Storyboards/Filter.storyboard b/Announcer/Storyboards/Filter.storyboard index edf151a..3f70982 100644 --- a/Announcer/Storyboards/Filter.storyboard +++ b/Announcer/Storyboards/Filter.storyboard @@ -14,7 +14,7 @@ - + @@ -42,7 +42,7 @@ - + @@ -98,7 +98,7 @@ - + diff --git a/Announcer/Support Files/Delegates/AppDelegate.swift b/Announcer/Support Files/Delegates/AppDelegate.swift index cd49516..f7c9f14 100644 --- a/Announcer/Support Files/Delegates/AppDelegate.swift +++ b/Announcer/Support Files/Delegates/AppDelegate.swift @@ -35,6 +35,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD center.requestAuthorization(options: options) { (granted, error) in if !granted { + // User did not give us notification access :( print("Something went wrong") print("noooo i demand notifications!!!!!") } @@ -66,12 +67,32 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD // Start background task scheduleBackgroundTaskIfNeeded() + // Set project version + let versionNumber = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String + UserDefaults.standard.set(versionNumber, forKey: "versionNumber") + + // Set project build + let buildNumber = Bundle.main.infoDictionary?["CFBundleVersion"] as! String + UserDefaults.standard.set(buildNumber, forKey: "buildNumber") + return true } - // Testing if background task works - // Run this below in debugger - // e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"sg.edu.sst.panziyue.Announcer.new-announcement"] + /** + Schedules the new announcement background task + + The identifier is `sg.edu.sst.panziyue.Announcer.new-announcement` + + --- + # Debugging Background Tasks + Running this line in the debugger to instantly manually background refresh. Background refresh takes a while so this is the easier way to do it and test it out. + + [Developer Article](https://developer.apple.com/documentation/backgroundtasks/starting_and_terminating_tasks_during_development) + + ``` + e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"sg.edu.sst.panziyue.Announcer.new-announcement"] + ``` + */ func scheduleBackgroundTaskIfNeeded() { let taskRequest = BGProcessingTaskRequest(identifier: AppDelegate.backgroundTaskIdentifier) taskRequest.requiresNetworkConnectivity = true @@ -131,9 +152,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } // Calls when user opens app from a notification - func userNotificationCenter(_ center: UNUserNotificationCenter, - didReceive response: UNNotificationResponse, - withCompletionHandler completionHandler: @escaping () -> Void) { + func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { openPost(with: response.notification) diff --git a/Announcer/Support Files/Globals.swift b/Announcer/Support Files/Globals.swift index f6a323b..152bee9 100644 --- a/Announcer/Support Files/Globals.swift +++ b/Announcer/Support Files/Globals.swift @@ -20,10 +20,10 @@ import SafariServices - important: Ensure that the URL is set to the correct blog before production. # Production Blog URL - http://studentsblog.sst.edu.sg + [http://studentsblog.sst.edu.sg](http://studentsblog.sst.edu.sg) # Development Blog URL - https://testannouncer.blogspot.com + [https://testannouncer.blogspot.com](https://testannouncer.blogspot.com) This constant stores the URL for the blog linked to the RSS feed. */ @@ -428,7 +428,6 @@ func launchPost(withTitle postTitle: String) { if let post = post { // Handles when post is found - announcementVC.receivePost(with: post) } else { diff --git a/Announcer/Support Files/Settings.bundle/Acknowledgements.plist b/Announcer/Support Files/Settings.bundle/Acknowledgements.plist index 5a59720..d21311d 100644 --- a/Announcer/Support Files/Settings.bundle/Acknowledgements.plist +++ b/Announcer/Support Files/Settings.bundle/Acknowledgements.plist @@ -107,8 +107,6 @@ SOFTWARE. Type PSGroupSpecifier - Title - Generated by Cocoapods - https://cocoapods.org diff --git a/Announcer/Support Files/Settings.bundle/Root.plist b/Announcer/Support Files/Settings.bundle/Root.plist index 0ace9ae..f48f44e 100644 --- a/Announcer/Support Files/Settings.bundle/Root.plist +++ b/Announcer/Support Files/Settings.bundle/Root.plist @@ -6,6 +6,32 @@ Root PreferenceSpecifiers + + Type + PSGroupSpecifier + Title + App Information + + + Type + PSTitleValueSpecifier + Title + Version + Key + versionNumber + DefaultValue + 0 + + + Type + PSTitleValueSpecifier + Title + Build + Key + buildNumber + DefaultValue + 0 + Type PSChildPaneSpecifier diff --git a/README.md b/README.md index 73ac144..fe56643 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # SST Announcer (iOS) [![Language](http://img.shields.io/badge/swift-5-orange.svg?style=flat)](https://developer.apple.com/swift) -[![Xcode](http://img.shields.io/badge/xcode-11.4-red.svg?style=flat)](https://developer.apple.com/xcode) +[![Xcode](http://img.shields.io/badge/xcode-11.5-red.svg?style=flat)](https://developer.apple.com/xcode) [![Cocoapods](http://img.shields.io/badge/pod-v1.8.4-darkgray.svg?style=flat)](https://cocoapods.org/) [![iOS](http://img.shields.io/badge/platform-iOS%2013-blue.svg?style=flat)](https://developer.apple.com/iphone/index.action) @@ -79,10 +79,10 @@ These colors are used for different parts of the app such as backgrounds and lab |Color Name |Identifier|Light Theme|Dark Theme | |-----------|----------|-----------|-----------| -|Background |`background`|![](https://via.placeholder.com/15/F5F4F6/F5F4F6) - #F5F4F6|![](https://via.placeholder.com/15/060400/060400) - #060400| -|Global Tint|`Global Tint`|![](https://via.placeholder.com/15/A9A9A9/A9A9A9) - #A9A9A9|![](https://via.placeholder.com/15/A9A9A9/A9A9A9) - #A9A9A9| -|Grey 1 |`Grey 1`|![](https://via.placeholder.com/15/434343/434343) - #434343|![](https://via.placeholder.com/15/B8BABB/B8BABB) - #B8BABB| -|Grey 2 |`Grey 2`|![](https://via.placeholder.com/15/DCDADB/DCDADB) - #DCDADB|![](https://via.placeholder.com/15/252628/252628) - #252628| +|Background |`"background"`|![](https://via.placeholder.com/15/F5F4F6/F5F4F6) - #F5F4F6|![](https://via.placeholder.com/15/060400/060400) - #060400| +|Global Tint|`"Global Tint"`|![](https://via.placeholder.com/15/A9A9A9/A9A9A9) - #A9A9A9|![](https://via.placeholder.com/15/A9A9A9/A9A9A9) - #A9A9A9| +|Grey 1 |`"Grey 1"`|![](https://via.placeholder.com/15/434343/434343) - #434343|![](https://via.placeholder.com/15/B8BABB/B8BABB) - #B8BABB| +|Grey 2 |`"Grey 2"`|![](https://via.placeholder.com/15/DCDADB/DCDADB) - #DCDADB|![](https://via.placeholder.com/15/252628/252628) - #252628| ### Apple Colors These colors are the ones as part of Apple's [UIColor Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/color/) @@ -97,6 +97,6 @@ These colors are used for loading content using KALoader |Color Name |Identifier|Light Theme|Dark Theme | |-----------|----------|-----------|-----------| -|First Load Color|`First Load Color`|![](https://via.placeholder.com/15/DEDEDE/DEDEDE) - #DEDEDE|![](https://via.placeholder.com/15/202020/202020) - #202020| -|Second Load Color|`Second Load Color`|![](https://via.placeholder.com/15/DDDDDD/DDDDDD) - #DDDDDD|![](https://via.placeholder.com/15/212121/212121) - #212121| -|Back Gray Color |`Back Gray Color`|![](https://via.placeholder.com/15/F6F6F6/F6F6F6) - #F6F6F6|![](https://via.placeholder.com/15/080808/080808) - #080808| +|First Load Color|`"First Load Color"`|![](https://via.placeholder.com/15/DEDEDE/DEDEDE) - #DEDEDE|![](https://via.placeholder.com/15/202020/202020) - #202020| +|Second Load Color|`"Second Load Color"`|![](https://via.placeholder.com/15/DDDDDD/DDDDDD) - #DDDDDD|![](https://via.placeholder.com/15/212121/212121) - #212121| +|Back Gray Color |`"Back Gray Color"`|![](https://via.placeholder.com/15/F6F6F6/F6F6F6) - #F6F6F6|![](https://via.placeholder.com/15/080808/080808) - #080808|