Dwayne Harris
6 years ago
12 changed files with 370 additions and 315 deletions
-
26elpha-ios.xcodeproj/project.pbxproj
-
8elpha-ios.xcodeproj/xcuserdata/Dwayne.xcuserdatad/xcschemes/xcschememanagement.plist
-
47elpha-ios/Base.lproj/Main.storyboard
-
52elpha-ios/Elpha.xcdatamodeld/Elpha.xcdatamodel/contents
-
16elpha-ios/InstanceViewController.swift
-
235elpha-ios/InstancesDataManager.swift
-
13elpha-ios/InstancesNavigationController.swift
-
15elpha-ios/InstancesTableView.swift
-
4elpha-ios/InstancesTableViewCell.swift
-
191elpha-ios/InstancesTableViewController.swift
-
56elpha-ios/WebViewController.swift
-
22elpha-ios/WebViewHelper.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<ISLanguageMO>(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<ISCategoryMO>(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<ISInstanceMO>(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() |
||||
|
} |
||||
|
} |
@ -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 { |
|
||||
|
|
||||
} |
|
@ -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) |
|
||||
} |
|
||||
} |
|
@ -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 |
|
||||
} |
|
||||
} |
|
@ -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") |
|
||||
} |
|
||||
} |
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue