diff options
-rw-r--r-- | foray.xcodeproj/project.pbxproj | 8 | ||||
-rw-r--r-- | foray/ForayItems.swift | 25 | ||||
-rw-r--r-- | foray/ForayNetworkManager.swift | 50 | ||||
-rw-r--r-- | foray/ForayTableViewController.swift | 83 |
4 files changed, 100 insertions, 66 deletions
diff --git a/foray.xcodeproj/project.pbxproj b/foray.xcodeproj/project.pbxproj index 6c2e2c4..9a09c0f 100644 --- a/foray.xcodeproj/project.pbxproj +++ b/foray.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + C011E4F127E6211400C248D6 /* ForayNetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C011E4F027E6211400C248D6 /* ForayNetworkManager.swift */; }; + C011E4F327E6216C00C248D6 /* ForayItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = C011E4F227E6216C00C248D6 /* ForayItems.swift */; }; C04B45A427DEF117001451A3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C04B45A327DEF117001451A3 /* AppDelegate.swift */; }; C04B45A627DEF117001451A3 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C04B45A527DEF117001451A3 /* SceneDelegate.swift */; }; C04B45AD27DEF118001451A3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C04B45AC27DEF118001451A3 /* Assets.xcassets */; }; @@ -17,6 +19,8 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + C011E4F027E6211400C248D6 /* ForayNetworkManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForayNetworkManager.swift; sourceTree = "<group>"; }; + C011E4F227E6216C00C248D6 /* ForayItems.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForayItems.swift; sourceTree = "<group>"; }; C04B45A027DEF117001451A3 /* foray.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = foray.app; sourceTree = BUILT_PRODUCTS_DIR; }; C04B45A327DEF117001451A3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; C04B45A527DEF117001451A3 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; }; @@ -62,7 +66,9 @@ C04B45A527DEF117001451A3 /* SceneDelegate.swift */, C0FEAF5E27E14C52000A7648 /* ForayDetailViewController.swift */, C04B45B727DEF2ED001451A3 /* ForayTableViewController.swift */, + C011E4F227E6216C00C248D6 /* ForayItems.swift */, C04EDE4327E4298D00D83005 /* ForayNewTableViewCell.swift */, + C011E4F027E6211400C248D6 /* ForayNetworkManager.swift */, C04B45AC27DEF118001451A3 /* Assets.xcassets */, C04B45B127DEF118001451A3 /* Info.plist */, ); @@ -144,10 +150,12 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + C011E4F127E6211400C248D6 /* ForayNetworkManager.swift in Sources */, C04B45B827DEF2ED001451A3 /* ForayTableViewController.swift in Sources */, C0FEAF5F27E14C52000A7648 /* ForayDetailViewController.swift in Sources */, C04EDE4427E4298D00D83005 /* ForayNewTableViewCell.swift in Sources */, C04B45A427DEF117001451A3 /* AppDelegate.swift in Sources */, + C011E4F327E6216C00C248D6 /* ForayItems.swift in Sources */, C04B45A627DEF117001451A3 /* SceneDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/foray/ForayItems.swift b/foray/ForayItems.swift new file mode 100644 index 0000000..f1a1089 --- /dev/null +++ b/foray/ForayItems.swift @@ -0,0 +1,25 @@ +// +// ForayItems.swift +// foray +// +// Created by Nicholas Tay on 20/3/2022. +// + +import Foundation + +enum ItemType: String, Decodable { + case item + case quest +} + +struct YearSection { + var year: Date + var items: [PenguinItem] +} + +struct PenguinItem: Decodable { + var type: ItemType + var releaseDate: Date + var id: String + var name: String +} diff --git a/foray/ForayNetworkManager.swift b/foray/ForayNetworkManager.swift new file mode 100644 index 0000000..ab1e2b5 --- /dev/null +++ b/foray/ForayNetworkManager.swift @@ -0,0 +1,50 @@ +// +// ForayNetworkManager.swift +// foray +// +// Created by Nicholas Tay on 20/3/2022. +// + +import Foundation + +class ForayNetworkManager { + static let shared = ForayNetworkManager() + + var basicUsername: String? = nil + var basicPassword: String? = nil + + // Reuse JSON decoder, allows for customisation of things like date decode if required + var jsonDecoder: JSONDecoder = { + let jd = JSONDecoder() + // Defaults to year-month-date format + jd.dateDecodingStrategy = .custom({ (decoder) -> Date in + let container = try decoder.singleValueContainer() + let dateStr = try container.decode(String.self) + + let dateFormat = DateFormatter() + dateFormat.dateFormat = "yyyy-MM-dd" + + return dateFormat.date(from: dateStr)! + }) + return jd + }() + + func get<T: Decodable>(url: String, + onComplete: @escaping ([T]) -> ()) { + var request = URLRequest(url: URL(string: url)!) + request.cachePolicy = .reloadRevalidatingCacheData // Needed otherwise default caching policy seems not to check properly + + // Basic auth if required + if (basicUsername != nil && basicPassword != nil) { + let authData = (basicUsername! + ":" + basicPassword!).data(using: .utf8)!.base64EncodedString() + request.addValue("Basic \(authData)", forHTTPHeaderField: "Authorization") + } + + URLSession.shared.dataTask(with: request, completionHandler: { data, response, error -> Void in + let items = try! self.jsonDecoder.decode([T].self, from: data!) + + // Possibly passing back to UI, need to do it on the main thread (I think due to async?) + DispatchQueue.main.async { onComplete(items) } + }).resume() + } +} diff --git a/foray/ForayTableViewController.swift b/foray/ForayTableViewController.swift index a7581d2..2732fce 100644 --- a/foray/ForayTableViewController.swift +++ b/foray/ForayTableViewController.swift @@ -7,29 +7,6 @@ import UIKit -enum ItemType: String, Decodable { - case item - case quest -} - -struct PenguinItem: Decodable { - var type: ItemType - var releaseDate: Date - var id: String - var name: String -} - -struct YearSection { - var year: Date - var items: [PenguinItem] -} - -private func parseDate(_ str : String) -> Date { - let dateFormat = DateFormatter() - dateFormat.dateFormat = "yyyy-MM-dd" - return dateFormat.date(from: str)! -} - private func firstDayOfYear(date: Date) -> Date { let calendar = Calendar.current let components = calendar.dateComponents([.year], from: date) @@ -75,50 +52,24 @@ class ForayTableViewController: UITableViewController { } func reloadApiData() { - loadApiData(onComplete: { (apiItems) in - var items = apiItems - items.sort { (lhs, rhs) in lhs.releaseDate < rhs.releaseDate } - - let groups = Dictionary(grouping: apiItems) { (item) in - return firstDayOfYear(date: item.releaseDate) - } - self.sections = groups.map { (key, values) in - return YearSection(year: key, items: values) - } - // Sort the sections from oldest year to newest - self.sections.sort { (lhs, rhs) in lhs.year < rhs.year } - - self.tableView.reloadData() - self.refreshControl?.endRefreshing() - }) - } - - func loadApiData(onComplete: @escaping ([PenguinItem]) -> ()) { - var request = URLRequest(url: URL(string: "https://users.windblume.net/~nick/upload/dummy.json")!) - request.cachePolicy = .reloadRevalidatingCacheData // Needed otherwise default caching policy seems not to check properly - - // Basic auth if required - //let authData = ("ext:PASSWORD").data(using: .utf8)!.base64EncodedString() - //request.addValue("Basic \(authData)", forHTTPHeaderField: "Authorization") - - URLSession.shared.dataTask(with: request, completionHandler: { data, response, error -> Void in - print("finished getting data") - print(response!) - - let jsonDecoder = JSONDecoder() - jsonDecoder.dateDecodingStrategy = .custom({ (decoder) -> Date in - let container = try decoder.singleValueContainer() - let dateStr = try container.decode(String.self) - return parseDate(dateStr) + ForayNetworkManager.shared.get( + url: "https://users.windblume.net/~nick/upload/dummy.json", + onComplete: { (apiItems: [PenguinItem]) in + var items = apiItems + items.sort { (lhs, rhs) in lhs.releaseDate < rhs.releaseDate } + + let groups = Dictionary(grouping: apiItems) { (item) in + return firstDayOfYear(date: item.releaseDate) + } + self.sections = groups.map { (key, values) in + return YearSection(year: key, items: values) + } + // Sort the sections from oldest year to newest + self.sections.sort { (lhs, rhs) in lhs.year < rhs.year } + + self.tableView.reloadData() + self.refreshControl?.endRefreshing() }) - let items = try! jsonDecoder.decode([PenguinItem].self, from: data!) - print("json decoded") - - // Passing back to UI, need to do it on the main thread (I think due to async?) - DispatchQueue.main.async { - onComplete(items) - } - }).resume() } // MARK: - Table view data source |