diff --git a/elpha-ios.xcodeproj/project.pbxproj b/elpha-ios.xcodeproj/project.pbxproj index 7a14391..6a8b7b2 100644 --- a/elpha-ios.xcodeproj/project.pbxproj +++ b/elpha-ios.xcodeproj/project.pbxproj @@ -8,8 +8,8 @@ /* Begin PBXBuildFile section */ 157405A82150588A00EEAAEB /* InstanceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 157405A72150588A00EEAAEB /* InstanceViewController.swift */; }; - 157405AA2150804200EEAAEB /* WebViewHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 157405A92150804200EEAAEB /* WebViewHelper.swift */; }; - 157405AC215080D400EEAAEB /* WebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 157405AB215080D400EEAAEB /* WebViewController.swift */; }; + 157405B12151A5DA00EEAAEB /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 157405AF2151A5DA00EEAAEB /* README.md */; }; + 157405B42151A93E00EEAAEB /* InstancesDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 157405B32151A93E00EEAAEB /* InstancesDataManager.swift */; }; 15830D93214F6F6F0037C342 /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15830D92214F6F6F0037C342 /* ImageCache.swift */; }; 159048AF214F5015004F4014 /* InstancesTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 159048AE214F5015004F4014 /* InstancesTableViewCell.swift */; }; 15960E5B213145E100C38CE9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15960E5A213145E100C38CE9 /* AppDelegate.swift */; }; @@ -27,14 +27,13 @@ 15960E8021353DCF00C38CE9 /* TimelineViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15960E7F21353DCF00C38CE9 /* TimelineViewController.swift */; }; 15960E822136668500C38CE9 /* TimelinesNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15960E812136668500C38CE9 /* TimelinesNavigationController.swift */; }; 15960E84213774FC00C38CE9 /* InstancesTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15960E83213774FC00C38CE9 /* InstancesTableViewController.swift */; }; - 15960E862137775D00C38CE9 /* InstancesNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15960E852137775D00C38CE9 /* InstancesNavigationController.swift */; }; - 15960E88213902A400C38CE9 /* InstancesTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15960E87213902A400C38CE9 /* InstancesTableView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 157405A72150588A00EEAAEB /* InstanceViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceViewController.swift; sourceTree = ""; }; - 157405A92150804200EEAAEB /* WebViewHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewHelper.swift; sourceTree = ""; }; - 157405AB215080D400EEAAEB /* WebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewController.swift; sourceTree = ""; }; + 157405AF2151A5DA00EEAAEB /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 157405B02151A5DA00EEAAEB /* Package.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; + 157405B32151A93E00EEAAEB /* InstancesDataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstancesDataManager.swift; sourceTree = ""; }; 15830D92214F6F6F0037C342 /* ImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCache.swift; sourceTree = ""; }; 159048AE214F5015004F4014 /* InstancesTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstancesTableViewCell.swift; sourceTree = ""; }; 15960E57213145E100C38CE9 /* elpha-ios.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "elpha-ios.app"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -54,8 +53,6 @@ 15960E7F21353DCF00C38CE9 /* TimelineViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineViewController.swift; sourceTree = ""; }; 15960E812136668500C38CE9 /* TimelinesNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelinesNavigationController.swift; sourceTree = ""; }; 15960E83213774FC00C38CE9 /* InstancesTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstancesTableViewController.swift; sourceTree = ""; }; - 15960E852137775D00C38CE9 /* InstancesNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstancesNavigationController.swift; sourceTree = ""; }; - 15960E87213902A400C38CE9 /* InstancesTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstancesTableView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -72,6 +69,8 @@ 15960E4E213145E100C38CE9 = { isa = PBXGroup; children = ( + 157405AF2151A5DA00EEAAEB /* README.md */, + 157405B02151A5DA00EEAAEB /* Package.swift */, 15960E59213145E100C38CE9 /* elpha-ios */, 15960E58213145E100C38CE9 /* Products */, ); @@ -93,7 +92,7 @@ 15960E7B213272CD00C38CE9 /* AuthenticationManager.swift */, 15960E7621322C6F00C38CE9 /* Configuration.swift */, 15830D92214F6F6F0037C342 /* ImageCache.swift */, - 157405A92150804200EEAAEB /* WebViewHelper.swift */, + 157405B32151A93E00EEAAEB /* InstancesDataManager.swift */, 15960E63213145E200C38CE9 /* Assets.xcassets */, 15960E6E21321FA500C38CE9 /* Elpha.xcdatamodeld */, 15960E7121322B9F00C38CE9 /* Keychain Helper */, @@ -117,8 +116,6 @@ isa = PBXGroup; children = ( 15960E7D21329FED00C38CE9 /* AuthenticateViewController.swift */, - 15960E852137775D00C38CE9 /* InstancesNavigationController.swift */, - 15960E87213902A400C38CE9 /* InstancesTableView.swift */, 159048AE214F5015004F4014 /* InstancesTableViewCell.swift */, 15960E83213774FC00C38CE9 /* InstancesTableViewController.swift */, 157405A72150588A00EEAAEB /* InstanceViewController.swift */, @@ -126,7 +123,6 @@ 15960E5E213145E100C38CE9 /* SecondViewController.swift */, 15960E812136668500C38CE9 /* TimelinesNavigationController.swift */, 15960E7F21353DCF00C38CE9 /* TimelineViewController.swift */, - 157405AB215080D400EEAAEB /* WebViewController.swift */, ); name = "View Controllers"; sourceTree = ""; @@ -192,6 +188,7 @@ files = ( 15960E67213145E200C38CE9 /* LaunchScreen.storyboard in Resources */, 15960E64213145E200C38CE9 /* Assets.xcassets in Resources */, + 157405B12151A5DA00EEAAEB /* README.md in Resources */, 15960E62213145E100C38CE9 /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -203,15 +200,13 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 157405AC215080D400EEAAEB /* WebViewController.swift in Sources */, - 15960E88213902A400C38CE9 /* InstancesTableView.swift in Sources */, 159048AF214F5015004F4014 /* InstancesTableViewCell.swift in Sources */, 15830D93214F6F6F0037C342 /* ImageCache.swift in Sources */, 15960E84213774FC00C38CE9 /* InstancesTableViewController.swift in Sources */, 15960E7021321FA500C38CE9 /* Elpha.xcdatamodeld in Sources */, + 157405B42151A93E00EEAAEB /* InstancesDataManager.swift in Sources */, 15960E5F213145E100C38CE9 /* SecondViewController.swift in Sources */, 15960E8021353DCF00C38CE9 /* TimelineViewController.swift in Sources */, - 157405AA2150804200EEAAEB /* WebViewHelper.swift in Sources */, 15960E7A2132387A00C38CE9 /* MainTabBarController.swift in Sources */, 15960E7C213272CD00C38CE9 /* AuthenticationManager.swift in Sources */, 15960E7E21329FED00C38CE9 /* AuthenticateViewController.swift in Sources */, @@ -220,7 +215,6 @@ 15960E7521322BF800C38CE9 /* KeychainWrapper.swift in Sources */, 157405A82150588A00EEAAEB /* InstanceViewController.swift in Sources */, 15960E7321322BC700C38CE9 /* KeychainItemAccessibility.swift in Sources */, - 15960E862137775D00C38CE9 /* InstancesNavigationController.swift in Sources */, 15960E822136668500C38CE9 /* TimelinesNavigationController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/elpha-ios.xcodeproj/xcuserdata/Dwayne.xcuserdatad/xcschemes/xcschememanagement.plist b/elpha-ios.xcodeproj/xcuserdata/Dwayne.xcuserdatad/xcschemes/xcschememanagement.plist index 409b554..546548b 100644 --- a/elpha-ios.xcodeproj/xcuserdata/Dwayne.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/elpha-ios.xcodeproj/xcuserdata/Dwayne.xcuserdatad/xcschemes/xcschememanagement.plist @@ -10,5 +10,13 @@ 0 + SuppressBuildableAutocreation + + 15960E56213145E100C38CE9 + + primary + + + diff --git a/elpha-ios/Base.lproj/Main.storyboard b/elpha-ios/Base.lproj/Main.storyboard index 2c52f5c..14c7d56 100644 --- a/elpha-ios/Base.lproj/Main.storyboard +++ b/elpha-ios/Base.lproj/Main.storyboard @@ -128,52 +128,11 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -472,10 +431,10 @@ - + - + diff --git a/elpha-ios/Elpha.xcdatamodeld/Elpha.xcdatamodel/contents b/elpha-ios/Elpha.xcdatamodeld/Elpha.xcdatamodel/contents index ea32c0b..af08bea 100644 --- a/elpha-ios/Elpha.xcdatamodeld/Elpha.xcdatamodel/contents +++ b/elpha-ios/Elpha.xcdatamodeld/Elpha.xcdatamodel/contents @@ -1,5 +1,5 @@ - + @@ -20,39 +20,63 @@ + + - - - + + + + + + + + + + - + + + + - + + - - + + + + + - + + + + + + + - - + + - - - + + + + + \ No newline at end of file diff --git a/elpha-ios/InstanceViewController.swift b/elpha-ios/InstanceViewController.swift index 3640fa0..f4b986d 100644 --- a/elpha-ios/InstanceViewController.swift +++ b/elpha-ios/InstanceViewController.swift @@ -8,23 +8,25 @@ import Foundation import UIKit +import SafariServices -class InstanceViewController: UIViewController { +class InstanceViewController: UIViewController, SFSafariViewControllerDelegate { @IBOutlet var thumbnailImageView: UIImageView! @IBOutlet var instanceNameLabel: UILabel! @IBOutlet var instanceDescriptionLabel: UILabel! @IBOutlet var webViewButton: UIButton! - var instance: Instance? = nil + var instance: ISInstanceMO? = nil @IBAction func webViewButtonPressed(_ sender: Any) { guard let instance = instance, let name = instance.name else { return } - if let webViewController = WebViewHelper.getWebViewController(url: URL(string: "https://\(name)")!) { - navigationController?.pushViewController(webViewController, animated: true) - } + let safariViewController = SFSafariViewController(url: URL(string: "https://\(name)")!) + safariViewController.delegate = self + + present(safariViewController, animated: true) } @@ -52,8 +54,8 @@ class InstanceViewController: UIViewController { instanceDescriptionLabel.text = instance.fullDescription } - if let thumbnailURL = instance.thumbnail { - ImageCache.shared.getImage(forURL: URL(string: thumbnailURL)!) { image, error in + if let thumbnail = instance.thumbnail { + ImageCache.shared.getImage(forURL: thumbnail) { image, error in guard error == nil else { return } diff --git a/elpha-ios/InstancesDataManager.swift b/elpha-ios/InstancesDataManager.swift new file mode 100644 index 0000000..8537b89 --- /dev/null +++ b/elpha-ios/InstancesDataManager.swift @@ -0,0 +1,235 @@ +// +// InstancesDataManager.swift +// elpha-ios +// +// Created by Dwayne Harris on 9/18/18. +// Copyright © 2018 Elpha. All rights reserved. +// + +import CoreData +import Foundation +import UIKit + +class InstancesDataManager { + static let shared = InstancesDataManager() + + let instanceRequestCount = 20 + var instances: [ISInstanceMO] = [] + var finished = false + var nextID: String? = nil + + static func upsertLanguage(string: String) -> ISLanguageMO? { + let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext + let request = NSFetchRequest(entityName: "ISLanguage") + request.predicate = NSPredicate(format: "id == %@", string) + + do { + let results: [ISLanguageMO] = try context.fetch(request) + switch results.count { + case 0: + let language = ISLanguageMO(context: context) + language.id = string + try context.save() + + return language + case 1: + return results.first + default: + print("Duplicate ISLanguage entity") + return nil + } + } catch { + print("\(error)") + return nil + } + } + + static func upsertCategory(string: String) -> ISCategoryMO? { + let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext + let request = NSFetchRequest(entityName: "ISCategory") + request.predicate = NSPredicate(format: "id == %@", string) + + do { + let results: [ISCategoryMO] = try context.fetch(request) + switch results.count { + case 0: + let category = ISCategoryMO(context: context) + category.id = string + try context.save() + + return category + case 1: + return results.first + default: + print("Duplicate ISCategory entity") + return nil + } + } catch { + print("\(error)") + return nil + } + } + + static func setAttributes(on i: ISInstanceMO, attributes: [String: Any]) { + guard let id = attributes["id"] as? String, let name = attributes["name"] as? String else { + print("Error") + return + } + + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ" + dateFormatter.locale = Locale(identifier: "en_US_POSIX") + + i.id = id + i.name = name + i.url = URL(string: "https://\(name)")! + i.uptime = attributes["uptime"] as! Int32 + i.up = attributes["up"] as! Bool + i.dead = attributes["dead"] as! Bool + i.version = attributes["version"] as? String + i.ipv6 = attributes["ipv6"] as! Bool + i.users = Int64(attributes["users"] as! String)! + i.statuses = Int64(attributes["statuses"] as! String)! + i.connections = Int64(attributes["connections"] as! String)! + i.openRegistrations = attributes["open_registrations"] as! Bool + + if let activeUsers = attributes["active_users"] as? Int64 { + i.activeUsers = activeUsers + } + + if let updatedAt = attributes["updated_at"] as? String { + i.updatedAt = dateFormatter.date(from: updatedAt) + } + + if let checkedAt = attributes["checked_at"] as? String { + i.checkedAt = dateFormatter.date(from: checkedAt) + } + + if let thumbnail = attributes["thumbnail"] as? String { + i.thumbnail = URL(string: thumbnail)! + } + + if let info = attributes["info"] as? [String: Any] { + i.shortDesc = info["short_description"] as? String + i.fullDescription = info["full_description"] as? String + i.topic = info["topic"] as? String + + for language in info["languages"] as! [String] { + if let l = upsertLanguage(string: language) { + i.mutableSetValue(forKey: "languages").add(l) + } + } + + for category in info["categories"] as! [String] { + if let c = upsertCategory(string: category) { + i.mutableSetValue(forKey: "categories").add(c) + } + } + } + } + + func reloadInstances(completion: @escaping (Error?) -> Void) { + finished = false + nextID = nil + loadInstances(completion: completion) + } + + func loadInstances(completion: @escaping (Error?) -> Void) { + var params = [ + "count=\(instanceRequestCount)", + "sort_by=users", + "sort_order=desc", + "include_closed=true", + "include_down=false", + ] + + if let nextID = nextID { + params.append("min_id=\(nextID)") + } + + let requestURL = "\(Config.instancesServiceUrl)\(Config.instancesServiceEndpoint)?\(params.joined(separator: "&"))" + print("loading instances: requestURL: \(requestURL)") + + var request = URLRequest(url: URL(string: requestURL)!) + request.addValue("Bearer \(Config.instancesServiceSecret)", forHTTPHeaderField: "Authorization") + + URLSession.shared.dataTask(with: request) { data, response, error in + guard error == nil else { + completion(error) + return + } + + guard let response = response as? HTTPURLResponse else { + print("No HTTP response") + completion(NSError()) + return + } + + switch response.statusCode { + case 200..<300: + guard let data = data else { + print("No HTTP response") + completion(NSError()) + return + } + + DispatchQueue.main.async { + do { + let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext + let instancesResult = try JSONSerialization.jsonObject(with: data) as! [String: Any] + + if let pagination = instancesResult["pagination"] as? [String: Any] { + if let nextID = pagination["next_id"] as? String { + self.nextID = nextID + } else { + self.nextID = nil + self.finished = true + } + } + + if let instances = instancesResult["instances"] as? [Any] { + for case let instance as [String: Any] in instances { + if let id = instance["id"] as? String { + let request = NSFetchRequest(entityName: "ISInstance") + request.predicate = NSPredicate(format: "id == %@", id) + + let results: [ISInstanceMO] = try context.fetch(request) + + switch results.count { + case 0: + let i = ISInstanceMO(context: context) + InstancesDataManager.setAttributes(on: i, attributes: instance) + case 1: + if let i = results.first { + InstancesDataManager.setAttributes(on: i, attributes: instance) + } + default: + print("Duplicate Instance entity") + } + } + } + + do { + try context.save() + } catch { + completion(error) + return + } + } + + completion(nil) + } catch { + completion(error) + return + } + } + case 400: + print("instances.social: 400") + completion(NSError()) + default: + completion(nil) + return + } + }.resume() + } +} diff --git a/elpha-ios/InstancesNavigationController.swift b/elpha-ios/InstancesNavigationController.swift deleted file mode 100644 index bd21a16..0000000 --- a/elpha-ios/InstancesNavigationController.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// InstancesNavigationController.swift -// elpha-ios -// -// Created by Dwayne Harris on 8/29/18. -// Copyright © 2018 Elpha. All rights reserved. -// - -import UIKit - -class InstancesNavigationController: UINavigationController { - -} diff --git a/elpha-ios/InstancesTableView.swift b/elpha-ios/InstancesTableView.swift deleted file mode 100644 index 447630e..0000000 --- a/elpha-ios/InstancesTableView.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// InstancesTableView.swift -// elpha-ios -// -// Created by Dwayne Harris on 8/30/18. -// Copyright © 2018 Elpha. All rights reserved. -// - -import UIKit - -class InstancesTableView: UITableView { - required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - } -} diff --git a/elpha-ios/InstancesTableViewCell.swift b/elpha-ios/InstancesTableViewCell.swift index d6e3076..16ad5e4 100644 --- a/elpha-ios/InstancesTableViewCell.swift +++ b/elpha-ios/InstancesTableViewCell.swift @@ -15,10 +15,10 @@ class InstancesTableViewCell: UITableViewCell { @IBOutlet var statusesLabel: UILabel! @IBOutlet var usersLabel: UILabel! - var thumbnailURL: String? { + var thumbnailURL: URL? { didSet { if let thumbnailURL = thumbnailURL { - ImageCache.shared.getImage(forURL: URL(string: thumbnailURL)!) { image, error in + ImageCache.shared.getImage(forURL: thumbnailURL) { image, error in guard error == nil else { return } diff --git a/elpha-ios/InstancesTableViewController.swift b/elpha-ios/InstancesTableViewController.swift index 6daae8e..07cd203 100644 --- a/elpha-ios/InstancesTableViewController.swift +++ b/elpha-ios/InstancesTableViewController.swift @@ -39,11 +39,6 @@ struct Instance { class InstancesTableViewController: UITableViewController, UIViewControllerPreviewingDelegate { @IBOutlet var mainNavigationItem: UINavigationItem! - let instanceRequestCount = 20 - var instances: [Instance] = [] - var nextID: String? = nil - var finished: Bool = false - var loading: Bool = false { didSet { DispatchQueue.main.async { @@ -76,118 +71,54 @@ class InstancesTableViewController: UITableViewController, UIViewControllerPrevi } @objc func reloadInstances() { - self.nextID = nil - self.finished = false - - loadInstances() - } - - func loadInstances() { loading = true - var params = [ - "count=\(instanceRequestCount)", - "sort_by=users", - "sort_order=desc", - "include_closed=true", - "include_down=false", - ] - - if let nextID = nextID { - params.append("min_id=\(nextID)") - } else { - instances = [] - + InstancesDataManager.shared.reloadInstances() { error in + self.loading = false + + guard error == nil else { + return + } + DispatchQueue.main.async { self.tableView.reloadData() } } + } + + func loadInstances() { + loading = true - let requestURL = "\(Config.instancesServiceUrl)\(Config.instancesServiceEndpoint)?\(params.joined(separator: "&"))" - - print("loading instances: requestURL: \(requestURL)") - - var request = URLRequest(url: URL(string: requestURL)!) - request.addValue("Bearer \(Config.instancesServiceSecret)", forHTTPHeaderField: "Authorization") - - let dataTask = URLSession.shared.dataTask(with: request) { data, response, error in + InstancesDataManager.shared.loadInstances() { error in + self.loading = false + guard error == nil else { return } - defer { - self.loading = false - } - - if let response = response as? HTTPURLResponse { - switch response.statusCode { - case 200..<300: - if let data = data { - do { - let instancesResult = try JSONSerialization.jsonObject(with: data) as! [String: Any] - - if let pagination = instancesResult["pagination"] as? [String: Any] { - if let nextID = pagination["next_id"] as? String { - self.nextID = nextID - } else { - self.nextID = nil - self.finished = true - } - } - - if let instances = instancesResult["instances"] as? [Any] { - for case let instance as [String: Any] in instances { - var i = Instance() - i.id = instance["id"] as? String - i.name = instance["name"] as? String - i.addedAt = instance["added_at"] as? String - i.updatedAt = instance["updated_at"] as? String - i.checkedAt = instance["checked_at"] as? String - i.uptime = instance["uptime"] as? Int - i.up = instance["up"] as? Bool - i.dead = instance["dead"] as? Bool - i.version = instance["version"] as? String - i.ipv6 = instance["ipv6"] as? Bool - i.httpsScore = instance["https_score"] as? Int - i.httpsRank = instance["https_rank"] as? String - i.users = instance["users"] as? String - i.statuses = instance["statuses"] as? String - i.connections = instance["connections"] as? Int - i.openRegistrations = instance["open_registrations"] as? Bool - i.thumbnail = instance["thumbnail"] as? String - i.thumbnailProxy = instance["thumbnail_proxy"] as? String - i.activeUsers = instance["active_users"] as? Int - - let info = instance["info"] as? [String: Any] - if let info = info { - i.shortDescription = info["short_description"] as? String - i.fullDescription = info["full_description"] as? String - i.topic = info["topic"] as? String - i.languages = info["languages"] as? [String] - i.categories = info["categories"] as? [String] - } - - self.instances.append(i) - } - - DispatchQueue.main.async { - self.tableView.reloadData() - } - } - } catch let error { - print(error) - return - } - } - case 400: - print("instances.social: 400") - default: - return - } + DispatchQueue.main.async { + self.tableView.reloadData() } } + } + + func getInstancesRequest() -> NSFetchRequest { + let request = NSFetchRequest(entityName: "ISInstance") + let sort = NSSortDescriptor(key: "users", ascending: false) + request.sortDescriptors = [sort] - dataTask.resume() + return request + } + + func getInstance(for indexPath: IndexPath) -> ISInstanceMO? { + let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext + + do { + let instances = try context.fetch(self.getInstancesRequest()) + return instances[indexPath.row] + } catch { + return nil + } } override func numberOfSections(in tableView: UITableView) -> Int { @@ -195,40 +126,48 @@ class InstancesTableViewController: UITableViewController, UIViewControllerPrevi } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return instances.count + let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext + + do { + return try context.count(for: self.getInstancesRequest()) + } catch { + return 0 + } } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext + guard let cell = tableView.dequeueReusableCell(withIdentifier: "InstancesTableViewCell", for: indexPath) as? InstancesTableViewCell else { fatalError("Unable to find reusable cell") } - let instance = instances[indexPath.row] - cell.instanceNameLabel.text = instance.name - - if let statuses = instance.statuses { - cell.statusesLabel.text = NumberFormatter.localizedString(from: NSNumber(value: Int64(statuses)!), number: .decimal) - } - - if let users = instance.users { - cell.usersLabel.text = NumberFormatter.localizedString(from: NSNumber(value: Int64(users)!), number: .decimal) - } - - if let thumbnail = instance.thumbnail { - cell.thumbnailURL = thumbnail - } - - if indexPath.row == instances.count - 1 && !loading && !finished { - loadInstances() + do { + let instances = try context.fetch(self.getInstancesRequest()) + let instance = instances[indexPath.row] + + cell.instanceNameLabel.text = instance.name + cell.statusesLabel.text = NumberFormatter.localizedString(from: NSNumber(value: instance.statuses), number: .decimal) + cell.usersLabel.text = NumberFormatter.localizedString(from: NSNumber(value: instance.users), number: .decimal) + + if let thumbnail = instance.thumbnail { + cell.thumbnailURL = thumbnail + } + + if indexPath.row == instances.count - 1 && !loading && !InstancesDataManager.shared.finished { + loadInstances() + } + + return cell + } catch { + return cell } - - return cell } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "InstanceDetailSegue", let cell = segue.destination as? InstanceViewController { - if let row = tableView.indexPathForSelectedRow?.row { - cell.instance = instances[row] + if let indexPath = tableView.indexPathForSelectedRow { + cell.instance = getInstance(for: indexPath) } } } @@ -240,7 +179,7 @@ class InstancesTableViewController: UITableViewController, UIViewControllerPrevi let storyboard = UIStoryboard(name: "Main", bundle: nil) if let detailViewController = storyboard.instantiateViewController(withIdentifier: "InstanceViewController") as? InstanceViewController { - detailViewController.instance = instances[indexPath.row] + detailViewController.instance = getInstance(for: indexPath) return detailViewController } else { return nil diff --git a/elpha-ios/WebViewController.swift b/elpha-ios/WebViewController.swift deleted file mode 100644 index 707e29b..0000000 --- a/elpha-ios/WebViewController.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// WebViewController.swift -// elpha-ios -// -// Created by Dwayne Harris on 9/17/18. -// Copyright © 2018 Elpha. All rights reserved. -// - -import Foundation -import UIKit -import WebKit - -class WebViewController: UIViewController, WKNavigationDelegate { - @IBOutlet var mainWebView: WKWebView! - @IBOutlet var mainProgressView: UIProgressView! - - var url: URL? = nil - - override func viewDidLoad() { - super.viewDidLoad() - - UINavigationBar.appearance().titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white] - - mainWebView.navigationDelegate = self - mainWebView.addObserver(self, forKeyPath: #keyPath(WKWebView.title), options: .new, context: nil) - mainWebView.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: .new, context: nil) - - if let url = url { - mainWebView.load(URLRequest(url: url)) - } - } - - @objc func done() { - dismiss(animated: true, completion: nil) - } - - override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { - if keyPath == #keyPath(WKWebView.title) { - if let title = mainWebView.title { - navigationItem.title = title - } - } - - if keyPath == #keyPath(WKWebView.estimatedProgress) { - mainProgressView.progress = Float(mainWebView.estimatedProgress) - } - } - - func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { - mainProgressView.alpha = 1.0 - } - - func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { - mainProgressView.alpha = 0.0 - } -} diff --git a/elpha-ios/WebViewHelper.swift b/elpha-ios/WebViewHelper.swift deleted file mode 100644 index 5a8f2f8..0000000 --- a/elpha-ios/WebViewHelper.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// WebViewHelper.swift -// elpha-ios -// -// Created by Dwayne Harris on 9/17/18. -// Copyright © 2018 Elpha. All rights reserved. -// - -import Foundation -import UIKit - -class WebViewHelper { - static func getWebViewController(url: URL) -> WebViewController? { - let storyboard = UIStoryboard(name: "Main", bundle: nil) - if let webViewController = storyboard.instantiateViewController(withIdentifier: "WebViewController") as? WebViewController { - webViewController.url = url - return webViewController - } - - fatalError("Could not instantiate WebViewController") - } -}