diff --git a/Cartfile b/Cartfile index bb1f830..c82a4bb 100644 --- a/Cartfile +++ b/Cartfile @@ -7,3 +7,4 @@ github "kishikawakatsumi/KeychainAccess" github "1024jp/GzipSwift" github "ashleymills/Reachability.swift" github "sparkle-project/Sparkle" +github "MessageKit/MessageKit" diff --git a/Cartfile.resolved b/Cartfile.resolved index b3aef3f..14c6bda 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,8 +1,10 @@ github "1024jp/GzipSwift" "5.1.1" github "BiAtoms/Socket.swift" "2.4.0" github "IBM-Swift/BlueRSA" "1.0.35" +github "MessageKit/MessageKit" "3.1.0" github "ashleymills/Reachability.swift" "v5.0.0" github "kishikawakatsumi/KeychainAccess" "v4.1.0" github "krzyzanowskim/CryptoSwift" "1.3.0" +github "nathantannar4/InputBarAccessoryView" "4.3.2" github "sindresorhus/Preferences" "v1.0.1" github "sparkle-project/Sparkle" "v1.23.0" diff --git a/README.md b/README.md index c6d2f9b..31b2757 100644 --- a/README.md +++ b/README.md @@ -26,26 +26,22 @@ https://developer.apple.com/library/archive/documentation/ToolsLanguages/Concept Minimal connection to a Wired 2.0 server: - // import module - import WiredSwfit - - // this automatically load P7 and Wired 2.0 specification let spec = P7Spec() - + // the Wired URL to connect to - let url = Url(withString: "wired://guest@locahost:4871") - + let url = Url(withString: "wired://192.168.1.23:4871") + // init connection let connection = Connection(withSpec: spec, delegate: self) connection.nick = "Me" connection.status = "Testing WiredSwift" - + // perform connect - if self.connection.connect(withUrl: url) { + if connection.connect(withUrl: url) { // connected } else { // not connected - print(self.connection.socket.errors) + print(connection.socket.errors) } ### Interactive socket diff --git a/Wired iOS/AppDelegate.swift b/Wired iOS/AppDelegate.swift index b016310..c2073a8 100644 --- a/Wired iOS/AppDelegate.swift +++ b/Wired iOS/AppDelegate.swift @@ -7,61 +7,106 @@ // import UIKit +import CoreData import WiredSwift_iOS +import Reachability -@UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate, ConnectionDelegate { - func connectionDidReceiveMessage(connection: Connection, message: P7Message) { - print("connectionDidReceiveMessage: \(message)") +extension UserDefaults { + func image(forKey key: String) -> UIImage? { + var image: UIImage? + if let imageData = data(forKey: key) { + image = try! NSKeyedUnarchiver.unarchivedObject(ofClass: UIImage.self, from: imageData) + } + return image } - - func connectionDidReceiveError(connection: Connection, message: P7Message) { - print("connectionDidReceiveError: \(message)") + func set(image: UIImage?, forKey key: String) { + var imageData: NSData? + if let image = image { + imageData = try! NSKeyedArchiver.archivedData(withRootObject: image, requiringSecureCoding: false) as NSData + } + set(imageData, forKey: key) } - - +} - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. - // this automatically load P7 and Wired 2.0 specification - let spec = P7Spec() - // the Wired URL to connect to - let url = Url(withString: "wired://192.168.1.23:4871") +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + public static let shared:AppDelegate = UIApplication.shared.delegate as! AppDelegate - // init connection - let connection = Connection(withSpec: spec, delegate: self) - connection.nick = "Me" - connection.status = "Testing WiredSwift" + var window:UIWindow? - // perform connect - if connection.connect(withUrl: url) { - // connected - - connection.joinChat(chatID: 1) - } else { - // not connected - print(connection.socket.errors) + override init() { + super.init() + + // Default preferences + UserDefaults.standard.register(defaults: [ + "WSUserNick": "WiredSwift", + "WSUserStatus": "Share The Wealth" + ]) + + if UserDefaults.standard.image(forKey: "WSUserIcon") == nil { + if let image = UIImage(named: "DefaultIcon") { + UserDefaults.standard.set(image: image, forKey: "WSUserIcon") + } } - return true + UserDefaults.standard.synchronize() } + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + Logger.setMaxLevel(.INFO) + + let splitViewController = window!.rootViewController as! UISplitViewController + splitViewController.preferredDisplayMode = UISplitViewController.DisplayMode.primaryOverlay - // MARK: UISceneSession Lifecycle - - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { - // Called when a new scene session is being created. - // Use this method to select a configuration to create the new scene with. - return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + return true } - func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { - // Called when the user discards a scene session. - // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. - // Use this method to release any resources that were specific to the discarded scenes, as they will not return. - } + + // MARK: - Core Data stack + + lazy var persistentContainer: NSPersistentContainer = { + /* + The persistent container for the application. This implementation + creates and returns a container, having loaded the store for the + application to it. This property is optional since there are legitimate + error conditions that could cause the creation of the store to fail. + */ + let container = NSPersistentContainer(name: "Wired3") + container.loadPersistentStores(completionHandler: { (storeDescription, error) in + if let error = error as NSError? { + // Replace this implementation with code to handle the error appropriately. + // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. + + /* + Typical reasons for an error here include: + * The parent directory does not exist, cannot be created, or disallows writing. + * The persistent store is not accessible, due to permissions or data protection when the device is locked. + * The device is out of space. + * The store could not be migrated to the current model version. + Check the error message to determine what the actual problem was. + */ + fatalError("Unresolved error \(error), \(error.userInfo)") + } + }) + return container + }() + // MARK: - Core Data Saving support + func saveContext () { + let context = persistentContainer.viewContext + if context.hasChanges { + do { + try context.save() + } catch { + // Replace this implementation with code to handle the error appropriately. + // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. + let nserror = error as NSError + fatalError("Unresolved error \(nserror), \(nserror.userInfo)") + } + } + } } diff --git a/Wired iOS/Assets.xcassets/ConnectionStatusConnected.imageset/AccountConnection_Ready-1.pdf b/Wired iOS/Assets.xcassets/ConnectionStatusConnected.imageset/AccountConnection_Ready-1.pdf new file mode 100644 index 0000000..0b84dc6 Binary files /dev/null and b/Wired iOS/Assets.xcassets/ConnectionStatusConnected.imageset/AccountConnection_Ready-1.pdf differ diff --git a/Wired iOS/Assets.xcassets/ConnectionStatusConnected.imageset/AccountConnection_Ready-2.pdf b/Wired iOS/Assets.xcassets/ConnectionStatusConnected.imageset/AccountConnection_Ready-2.pdf new file mode 100644 index 0000000..0b84dc6 Binary files /dev/null and b/Wired iOS/Assets.xcassets/ConnectionStatusConnected.imageset/AccountConnection_Ready-2.pdf differ diff --git a/Wired iOS/Assets.xcassets/ConnectionStatusConnected.imageset/AccountConnection_Ready.pdf b/Wired iOS/Assets.xcassets/ConnectionStatusConnected.imageset/AccountConnection_Ready.pdf new file mode 100644 index 0000000..0b84dc6 Binary files /dev/null and b/Wired iOS/Assets.xcassets/ConnectionStatusConnected.imageset/AccountConnection_Ready.pdf differ diff --git a/Wired iOS/Assets.xcassets/ConnectionStatusConnected.imageset/Contents.json b/Wired iOS/Assets.xcassets/ConnectionStatusConnected.imageset/Contents.json new file mode 100644 index 0000000..7b0b0e6 --- /dev/null +++ b/Wired iOS/Assets.xcassets/ConnectionStatusConnected.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "AccountConnection_Ready.pdf", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "AccountConnection_Ready-1.pdf", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "AccountConnection_Ready-2.pdf", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Wired iOS/Assets.xcassets/ConnectionStatusDisconnected.imageset/AccountConnection_Disabled-1.pdf b/Wired iOS/Assets.xcassets/ConnectionStatusDisconnected.imageset/AccountConnection_Disabled-1.pdf new file mode 100644 index 0000000..57f07bc Binary files /dev/null and b/Wired iOS/Assets.xcassets/ConnectionStatusDisconnected.imageset/AccountConnection_Disabled-1.pdf differ diff --git a/Wired iOS/Assets.xcassets/ConnectionStatusDisconnected.imageset/AccountConnection_Disabled-2.pdf b/Wired iOS/Assets.xcassets/ConnectionStatusDisconnected.imageset/AccountConnection_Disabled-2.pdf new file mode 100644 index 0000000..57f07bc Binary files /dev/null and b/Wired iOS/Assets.xcassets/ConnectionStatusDisconnected.imageset/AccountConnection_Disabled-2.pdf differ diff --git a/Wired iOS/Assets.xcassets/ConnectionStatusDisconnected.imageset/AccountConnection_Disabled.pdf b/Wired iOS/Assets.xcassets/ConnectionStatusDisconnected.imageset/AccountConnection_Disabled.pdf new file mode 100644 index 0000000..57f07bc Binary files /dev/null and b/Wired iOS/Assets.xcassets/ConnectionStatusDisconnected.imageset/AccountConnection_Disabled.pdf differ diff --git a/Wired iOS/Assets.xcassets/ConnectionStatusDisconnected.imageset/Contents.json b/Wired iOS/Assets.xcassets/ConnectionStatusDisconnected.imageset/Contents.json new file mode 100644 index 0000000..f331297 --- /dev/null +++ b/Wired iOS/Assets.xcassets/ConnectionStatusDisconnected.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "AccountConnection_Disabled.pdf", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "AccountConnection_Disabled-1.pdf", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "AccountConnection_Disabled-2.pdf", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Wired iOS/Assets.xcassets/DefaultUser.imageset/Contents.json b/Wired iOS/Assets.xcassets/DefaultUser.imageset/Contents.json new file mode 100644 index 0000000..36b80ba --- /dev/null +++ b/Wired iOS/Assets.xcassets/DefaultUser.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "WiredClient.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "WiredClient-2.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "WiredClient-1.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Wired iOS/Assets.xcassets/DefaultUser.imageset/WiredClient-1.png b/Wired iOS/Assets.xcassets/DefaultUser.imageset/WiredClient-1.png new file mode 100644 index 0000000..e716504 Binary files /dev/null and b/Wired iOS/Assets.xcassets/DefaultUser.imageset/WiredClient-1.png differ diff --git a/Wired iOS/Assets.xcassets/DefaultUser.imageset/WiredClient-2.png b/Wired iOS/Assets.xcassets/DefaultUser.imageset/WiredClient-2.png new file mode 100644 index 0000000..7fd7c3b Binary files /dev/null and b/Wired iOS/Assets.xcassets/DefaultUser.imageset/WiredClient-2.png differ diff --git a/Wired iOS/Assets.xcassets/DefaultUser.imageset/WiredClient.png b/Wired iOS/Assets.xcassets/DefaultUser.imageset/WiredClient.png new file mode 100644 index 0000000..db8943b Binary files /dev/null and b/Wired iOS/Assets.xcassets/DefaultUser.imageset/WiredClient.png differ diff --git a/Wired iOS/Assets.xcassets/Logo.imageset/Contents.json b/Wired iOS/Assets.xcassets/Logo.imageset/Contents.json new file mode 100644 index 0000000..a88b109 --- /dev/null +++ b/Wired iOS/Assets.xcassets/Logo.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "WiredClient-2.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "WiredClient-1.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "WiredClient.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Wired iOS/Assets.xcassets/Logo.imageset/WiredClient-1.png b/Wired iOS/Assets.xcassets/Logo.imageset/WiredClient-1.png new file mode 100644 index 0000000..f7e3125 Binary files /dev/null and b/Wired iOS/Assets.xcassets/Logo.imageset/WiredClient-1.png differ diff --git a/Wired iOS/Assets.xcassets/Logo.imageset/WiredClient-2.png b/Wired iOS/Assets.xcassets/Logo.imageset/WiredClient-2.png new file mode 100644 index 0000000..e716504 Binary files /dev/null and b/Wired iOS/Assets.xcassets/Logo.imageset/WiredClient-2.png differ diff --git a/Wired iOS/Assets.xcassets/Logo.imageset/WiredClient.png b/Wired iOS/Assets.xcassets/Logo.imageset/WiredClient.png new file mode 100644 index 0000000..37e3eed Binary files /dev/null and b/Wired iOS/Assets.xcassets/Logo.imageset/WiredClient.png differ diff --git a/Wired iOS/Base.lproj/LaunchScreen.storyboard b/Wired iOS/Base.lproj/LaunchScreen.storyboard index 865e932..c36f54e 100644 --- a/Wired iOS/Base.lproj/LaunchScreen.storyboard +++ b/Wired iOS/Base.lproj/LaunchScreen.storyboard @@ -1,7 +1,9 @@ - - + + + - + + @@ -11,9 +13,18 @@ - + - + + + + + + + + + + @@ -22,4 +33,7 @@ + + + diff --git a/Wired iOS/Base.lproj/Main.storyboard b/Wired iOS/Base.lproj/Main.storyboard index a504101..97e1c28 100644 --- a/Wired iOS/Base.lproj/Main.storyboard +++ b/Wired iOS/Base.lproj/Main.storyboard @@ -1,16 +1,19 @@ - + + - + + - + - + + @@ -21,43 +24,37 @@ - + - + - + - - - - - - - - - + - + + + + + + + + - + - + - + @@ -66,36 +63,53 @@ - + - + - + - + - + - - + + - + - + + + + + + + - + - + + @@ -105,17 +119,331 @@ - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -127,7 +455,11 @@ + + + + - + diff --git a/Wired iOS/BookmarkTableViewCell.swift b/Wired iOS/BookmarkTableViewCell.swift new file mode 100644 index 0000000..45b6f4f --- /dev/null +++ b/Wired iOS/BookmarkTableViewCell.swift @@ -0,0 +1,26 @@ +// +// UserTableViewCell.swift +// Wired iOS +// +// Created by Rafael Warnault on 01/04/2020. +// Copyright © 2020 Read-Write. All rights reserved. +// + +import UIKit + +class BookmarkTableViewCell: UITableViewCell { + @IBOutlet weak var nameLabel: UILabel! + @IBOutlet weak var statusImageView: UIImageView! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + // Configure the view for the selected state + } + +} diff --git a/Wired iOS/BookmarkViewController.swift b/Wired iOS/BookmarkViewController.swift new file mode 100644 index 0000000..86fc307 --- /dev/null +++ b/Wired iOS/BookmarkViewController.swift @@ -0,0 +1,64 @@ +// +// BookamrkViewController.swift +// Wired iOS +// +// Created by Rafael Warnault on 31/03/2020. +// Copyright © 2020 Read-Write. All rights reserved. +// + +import UIKit +import CoreData +import KeychainAccess +import WiredSwift_iOS + +class BookmarkViewController: UITableViewController { + @IBOutlet var addressTextField: UITextField! + @IBOutlet var loginTextField: UITextField! + @IBOutlet var passwordTextField: UITextField! + + public var masterViewController:BookmarksViewController! + + override func viewDidLoad() { + super.viewDidLoad() + + // Uncomment the following line to preserve selection between presentations + // self.clearsSelectionOnViewWillAppear = false + + // Uncomment the following line to display an Edit button in the navigation bar for this view controller. + //self.navigationItem.rightBarButtonItem = self.editButtonItem + addressTextField.becomeFirstResponder() + } + + + // MARK: - + + @IBAction func cancel(_ sender: Any) { + self.dismiss(animated: true) { } + } + + @IBAction func ok(_ sender: Any) { + // validate + if self.addressTextField.text == nil && self.addressTextField.text!.isEmpty || + self.loginTextField.text == nil && self.loginTextField.text!.isEmpty { + return + } + let context = AppDelegate.shared.persistentContainer.viewContext + let bookmark:Bookmark = NSEntityDescription.insertNewObject( + forEntityName: "Bookmark", into: context) as! Bookmark + + bookmark.name = self.addressTextField.text + bookmark.hostname = self.addressTextField.text + bookmark.login = self.loginTextField.text + + let keychain = Keychain(server: "wired://\(bookmark.hostname!)", protocolType: .irc) + keychain[bookmark.login!] = self.passwordTextField.text + + AppDelegate.shared.saveContext() + + self.masterViewController.reloadBookmarks() + + self.dismiss(animated: true) { } + } + + +} diff --git a/Wired iOS/BookmarksViewController.swift b/Wired iOS/BookmarksViewController.swift new file mode 100644 index 0000000..fbe7682 --- /dev/null +++ b/Wired iOS/BookmarksViewController.swift @@ -0,0 +1,306 @@ +// +// MasterViewController.swift +// Wired iOS +// +// Created by Rafael Warnault on 31/03/2020. +// Copyright © 2020 Read-Write. All rights reserved. +// + +import UIKit +import CoreData +import WiredSwift_iOS +import JGProgressHUD +import Reachability + + +class BookmarksViewController: UITableViewController, ConnectionDelegate { + let hud = JGProgressHUD(style: .dark) + //var chatViewController: ChatViewController? = nil + + var bookmarks = [Bookmark]() + var connections = [Bookmark:Connection]() + var chatViewControllers = [Connection:ChatViewController]() + + let reachability = try! Reachability() + + override func viewDidLoad() { + super.viewDidLoad() + + let userProfileButton = UIBarButtonItem(title: "Profile", style: .plain, target: self, action: #selector(showUserProfile(_:))) + navigationItem.leftBarButtonItem = userProfileButton + + self.reloadBookmarks() + + let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(insertNewObject(_:))) + navigationItem.rightBarButtonItem = addButton + + hud.textLabel.text = "Loading" + + if let split = self.splitViewController { + if UIApplication.shared.statusBarOrientation == .portrait { + UIView.animate(withDuration: 0.3, animations: { + split.preferredDisplayMode = .primaryOverlay + }, completion: nil) + } + } + } + + override func viewWillAppear(_ animated: Bool) { + //clearsSelectionOnViewWillAppear = splitViewController!.isCollapsed + super.viewWillAppear(animated) + } + + @objc + func insertNewObject(_ sender: Any) { + self.performSegue(withIdentifier: "ShowBookmark", sender: self) + } + + @objc + func showUserProfile(_ sender: Any) { + self.performSegue(withIdentifier: "ShowProfile", sender: self) + } + + + + // MARK: - IBAction + + @IBAction func connect(_ sender: Any) { + if let indexPath = tableView.indexPathForSelectedRow { + let bookmark = bookmarks[indexPath.row] + + let spec = P7Spec() + let url = bookmark.url() + + let connection = Connection(withSpec: spec, delegate: self) + connection.nick = UserDefaults.standard.string(forKey: "WSUserNick") ?? "Swift iOS" + connection.status = UserDefaults.standard.string(forKey: "WSUserStatus") ?? "Around" + + if let b64string = UserDefaults.standard.image(forKey: "WSUserIcon")?.pngData()?.base64EncodedString() { + connection.icon = b64string + } + + self.hud.show(in: self.view) + + // perform connect + DispatchQueue.global().async { + if connection.connect(withUrl: url) { + DispatchQueue.main.async { + self.hud.dismiss(afterDelay: 1.0) + + self.connections[bookmark] = connection + + self.performSegue(withIdentifier: "showDetail", sender: self) + + if let split = self.splitViewController { + UIView.animate(withDuration: 0.3, animations: { + split.preferredDisplayMode = .primaryHidden + }, completion: nil) + } + + // update bookmark with server name + bookmark.name = connection.serverInfo.serverName + AppDelegate.shared.saveContext() + self.tableView.reloadRows(at: [indexPath], with: .none) + } + + } else { + DispatchQueue.main.async { + self.hud.dismiss(afterDelay: 1.0) + // not connected + print(connection.socket.errors) + + let alertController = UIAlertController(title: "Connection Error", message: + "Enable to connect to \(bookmark.hostname!)", preferredStyle: .alert) + alertController.addAction(UIAlertAction(title: "OK", style: .default)) + + self.present(alertController, animated: true, completion: nil) + } + } + } + } + } + + + + // MARK: - Segues + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + if segue.identifier == "ShowBookmark" { + let controller = (segue.destination as! UINavigationController).topViewController as! BookmarkViewController + controller.masterViewController = self + } + else if segue.identifier == "showDetail" { + if let indexPath = tableView.indexPathForSelectedRow { + let bookmark = bookmarks[indexPath.row] + let controller = (segue.destination as! UINavigationController).topViewController as! ChatViewController + + controller.bookmark = bookmark + controller.connection = connections[bookmark] + self.chatViewControllers[controller.connection!] = controller + controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem + controller.navigationItem.leftItemsSupplementBackButton = true + } + } + } + + // MARK: - Segues + + @objc func showConnections() { + if let split = self.splitViewController { + if UIApplication.shared.statusBarOrientation == .portrait { + UIView.animate(withDuration: 0.3, animations: { + split.preferredDisplayMode = .primaryOverlay + }, completion: nil) + } + } + } + + // MARK: - Table View + + override func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return bookmarks.count + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as? BookmarkTableViewCell + + let bookmark = bookmarks[indexPath.row] + let connection = self.connections[bookmark] + + cell?.nameLabel!.text = bookmark.name + + if connection != nil && connection?.isConnected() == true { + cell?.statusImageView.image = UIImage(named: "ConnectionStatusConnected") + } else { + cell?.statusImageView.image = nil + } + + return cell! + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let bookmark = bookmarks[indexPath.row] + + if let connection = self.connections[bookmark] { + if connection.isConnected() == true { + if let controller = self.chatViewControllers[connection] { + if UIDevice.current.userInterfaceIdiom == .pad { + if let split = splitViewController { + print("split") + + if let navController = split.viewControllers[1] as? UINavigationController { + navController.viewControllers = [controller] + UIView.animate(withDuration: 0.3, animations: { + split.preferredDisplayMode = .primaryHidden + }, completion: nil) + } + } + } else { + print("push") + + self.navigationController?.pushViewController(controller, animated: true) + } + } + } + } else { + self.connect(self) + } + } + + override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { + // Return false if you do not want the specified item to be editable. + return true + } + + + override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { + if editingStyle == .delete { + let bookmark = bookmarks.remove(at: indexPath.row) + + AppDelegate.shared.persistentContainer.viewContext.delete(bookmark) + AppDelegate.shared.saveContext() + + tableView.deleteRows(at: [indexPath], with: .fade) + } else if editingStyle == .insert { + // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view. + } + } + + // MARK: - + + public func reloadBookmarks() { + let fetchRequest = NSFetchRequest(entityName: "Bookmark") + + guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { + return + } + + let context = appDelegate.persistentContainer.viewContext + + do { + let results = try context.fetch(fetchRequest) + let bookmarks = results as! [Bookmark] + + self.bookmarks = bookmarks + + } catch let error as NSError { + print("Could not fetch \(error)") + } + + self.tableView.reloadData() + } + + + // MARK: - + func connectionDisconnected(connection: Connection, error: Error?) { + if let controller = self.chatViewControllers[connection] { + if let bookmark = controller.bookmark { + self.connections.removeValue(forKey: bookmark) + self.chatViewControllers.removeValue(forKey: connection) + + self.tableView.reloadData() + } + } + } + + + func connectionDidReceiveMessage(connection: Connection, message: P7Message) { + + } + + func connectionDidReceiveError(connection: Connection, message: P7Message) { + + } + + + // MARK: - + + private func setupReachability() { + self.reachability.whenReachable = { _ in + + } + + self.reachability.whenUnreachable = { _ in + for b in self.bookmarks { + if let connection = self.connections[b] { + if connection.isConnected() { + connection.disconnect() + } + } + } + } + + do { + try self.reachability.startNotifier() + } catch { + + } + } +} + + + diff --git a/Wired iOS/ChatViewController.swift b/Wired iOS/ChatViewController.swift new file mode 100644 index 0000000..b715865 --- /dev/null +++ b/Wired iOS/ChatViewController.swift @@ -0,0 +1,272 @@ +// +// DetailViewController.swift +// Wired iOS +// +// Created by Rafael Warnault on 31/03/2020. +// Copyright © 2020 Read-Write. All rights reserved. +// + +import UIKit +import MessageKit +import WiredSwift_iOS + + +public struct Sender: SenderType { + public let senderId: String + + public let displayName: String +} + +public struct Message : MessageType { + public var sender: SenderType + + public var messageId: String + + public var sentDate: Date + + public var kind: MessageKind +} + +extension ChatViewController: MessagesDisplayDelegate, MessagesLayoutDelegate { + func configureAvatarView(_ avatarView: AvatarView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) { + if let userID = UInt32(message.sender.senderId) { + if let avatar = self.avatars[userID] { + avatarView.backgroundColor = UIColor.clear + avatarView.image = avatar.image + } + } + } + + func enabledDetectors(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> [DetectorType] { + return [.url] + } +} + + + +extension ChatViewController: MessagesDataSource { + func currentSender() -> SenderType { + return self.selfSender + } + + func messageForItem(at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageType { + return messages[indexPath.section] + } + + func numberOfSections(in messagesCollectionView: MessagesCollectionView) -> Int { + return self.messages.count + } +} + + +extension ChatViewController: MessageCellDelegate { + func didSelectURL(_ url: URL) { + UIApplication.shared.open(url) + } +} + + + +class ChatViewController: MessagesViewController, ConnectionDelegate { + @IBOutlet var infoButton: UIBarButtonItem! + + var selfSender:Sender = Sender(senderId: "-1", displayName: "Nark iOS") + var messages:[MessageType] = [] + var users:[UserInfo] = [] + var senders:[UInt32:Sender] = [:] + var avatars:[UInt32:Avatar] = [:] + var bookmark:Bookmark! + + + override func viewDidLoad() { + super.viewDidLoad() + + NotificationCenter.default.addObserver(self, selector: #selector(userDidUpdateProfile(_:)), name: .userDidUpdateProfile, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(willTerminateNotification(_ :)), name: UIApplication.willTerminateNotification, object: nil) + + messagesCollectionView.contentInset = UIEdgeInsets(top: 44, left: 0, bottom: 0, right: 0) + + messagesCollectionView.messagesDataSource = self + messagesCollectionView.messagesLayoutDelegate = self + messagesCollectionView.messagesDisplayDelegate = self + messagesCollectionView.messageCellDelegate = self + + messageInputBar.sendButton.addTarget(self, action: #selector(sendMessage), for: UIControl.Event.touchDown) + + configureView() + } + + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + + if let c = self.connection { + if c.isConnected() { + //c.disconnect() + } + } + } + + var connection: Connection? { + didSet { + // Update the view. + configureView() + + if let c = self.connection { + if c.isConnected() { + c.addDelegate(self) + + self.selfSender = Sender(senderId: "\(self.connection!.userID!)", displayName: "Wired iOS") + + _ = c.joinChat(chatID: 1) + } + } + } + } + + + func configureView() { + self.navigationItem.title = self.connection?.serverInfo.serverName + + if self.connection != nil && self.connection!.isConnected() { + self.infoButton.isEnabled = true + self.messageInputBar.isHidden = false + } else { + self.infoButton.isEnabled = false + self.messageInputBar.isHidden = true + } + } + + + + // MARK: - + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + if segue.identifier == "ShowServerInfo" { + if let controller = segue.destination as? ServerInfoViewController { + controller.users = self.users + controller.connection = self.connection + } + } + } + + + // MARK: - + @objc func popBack() { + self.navigationController?.popToRootViewController(animated: true) + } + + + // MARK: - + + @objc func willTerminateNotification(_ n:Notification) { + if self.connection != nil && self.connection!.isConnected() { + self.connection!.disconnect() + popBack() + } + } + + + @objc func userDidUpdateProfile(_ n:Notification) { + if self.connection != nil && self.connection!.isConnected() { + var message = P7Message(withName: "wired.user.set_nick", spec: self.connection!.spec) + + if let nick = UserDefaults.standard.string(forKey: "WSUserNick") { + message.addParameter(field: "wired.user.nick", value: nick) + } + + _ = self.connection?.send(message: message) + + message = P7Message(withName: "wired.user.set_status", spec: self.connection!.spec) + + if let status = UserDefaults.standard.string(forKey: "WSUserStatus") { + message.addParameter(field: "wired.user.status", value: status) + } + + _ = self.connection?.send(message: message) + + message = P7Message(withName: "wired.user.set_icon", spec: self.connection!.spec) + + if let icon = UserDefaults.standard.image(forKey: "WSUserIcon")?.pngData() { + message.addParameter(field: "wired.user.icon", value: icon) + } + + _ = self.connection?.send(message: message) + } + } + + + // MARK: - + + @objc func sendMessage() { + if let text = messageInputBar.inputTextView.text { + if self.connection != nil && self.connection!.isConnected() { + let message = P7Message(withName: "wired.chat.send_say", spec: self.connection!.spec) + message.addParameter(field: "wired.chat.id", value: UInt32(1)) + message.addParameter(field: "wired.user.id", value: UInt32(self.selfSender.senderId)) + message.addParameter(field: "wired.chat.say", value: text) + + if self.connection!.send(message: message) { + messageInputBar.inputTextView.text = "" + } + } + } + } + + + // MARK: - + func connectionDisconnected(connection: Connection, error: Error?) { + configureView() + + print("connectionDisconnected") + + let alertController = UIAlertController( + title: "Connection Error", + message: "You have beed disconnected from \(bookmark.hostname!)", + preferredStyle: .alert) + + alertController.addAction(UIAlertAction(title: "OK", style: .default)) + + self.present(alertController, animated: true) { + self.navigationController?.popToRootViewController(animated: true) + } + } + + func connectionDidReceiveMessage(connection: Connection, message: P7Message) { + if message.name == "wired.chat.say" || message.name == "wired.chat.me" { + if let userID = message.uint32(forField: "wired.user.id") { + let string = message.string(forField: "wired.chat.say") ?? message.string(forField: "wired.chat.me") + + if let s = string { + let uuid = UUID().uuidString + if let sender = self.senders[userID] { + let message = Message( + sender: sender, + messageId: uuid, + sentDate: Date(), + kind: MessageKind.attributedText(NSAttributedString(string: s))) + + self.messages.append(message) + + self.messagesCollectionView.reloadDataAndKeepOffset() + } + } + } + } + else if message.name == "wired.chat.user_list" { + if let userID = message.uint32(forField: "wired.user.id"), + let iconData = message.data(forField: "wired.user.icon"), + let nick = message.string(forField: "wired.user.nick") { + + self.users.append(UserInfo(message: message)) + self.senders[userID] = Sender(senderId: "\(userID)", displayName: nick) + self.avatars[userID] = Avatar(image: UIImage(data: iconData), initials: nick) + } + } + } + + func connectionDidReceiveError(connection: Connection, message: P7Message) { + + } + +} diff --git a/Wired iOS/DetailViewController.swift b/Wired iOS/DetailViewController.swift deleted file mode 100644 index 7eb92cc..0000000 --- a/Wired iOS/DetailViewController.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// DetailViewController.swift -// Wired iOS -// -// Created by Rafael Warnault on 31/03/2020. -// Copyright © 2020 Read-Write. All rights reserved. -// - -import UIKit - -class DetailViewController: UIViewController { - - @IBOutlet weak var detailDescriptionLabel: UILabel! - - - func configureView() { - // Update the user interface for the detail item. - if let detail = detailItem { - if let label = detailDescriptionLabel { - label.text = detail.description - } - } - } - - override func viewDidLoad() { - super.viewDidLoad() - // Do any additional setup after loading the view. - configureView() - } - - var detailItem: NSDate? { - didSet { - // Update the view. - configureView() - } - } - - -} - diff --git a/Wired iOS/Info.plist b/Wired iOS/Info.plist index 21af75f..764079e 100644 --- a/Wired iOS/Info.plist +++ b/Wired iOS/Info.plist @@ -20,27 +20,8 @@ 1 LSRequiresIPhoneOS - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneConfigurationName - Default Configuration - UISceneDelegateClassName - $(PRODUCT_MODULE_NAME).SceneDelegate - UISceneStoryboardFile - Main - - - - - UIBackgroundModes - + NSCameraUsageDescription + Taking pictures UILaunchStoryboardName LaunchScreen UIMainStoryboardFile diff --git a/Wired iOS/MainSplitViewController.swift b/Wired iOS/MainSplitViewController.swift new file mode 100644 index 0000000..66499bf --- /dev/null +++ b/Wired iOS/MainSplitViewController.swift @@ -0,0 +1,29 @@ +// +// MainSplitViewController.swift +// Wired iOS +// +// Created by Rafael Warnault on 01/04/2020. +// Copyright © 2020 Read-Write. All rights reserved. +// + +import UIKit + +class MainSplitViewController: UISplitViewController, UISplitViewControllerDelegate { + + override func viewDidLoad() { + super.viewDidLoad() + + self.delegate = self + } + + func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool { + guard let secondaryAsNavController = secondaryViewController as? UINavigationController else { return false } + guard let topAsDetailController = secondaryAsNavController.topViewController as? ChatViewController else { return false } + if topAsDetailController.connection == nil { + // Return true to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded. + return true + } + return false + } + +} diff --git a/Wired iOS/MasterViewController.swift b/Wired iOS/MasterViewController.swift deleted file mode 100644 index 5ef9536..0000000 --- a/Wired iOS/MasterViewController.swift +++ /dev/null @@ -1,90 +0,0 @@ -// -// MasterViewController.swift -// Wired iOS -// -// Created by Rafael Warnault on 31/03/2020. -// Copyright © 2020 Read-Write. All rights reserved. -// - -import UIKit - -class MasterViewController: UITableViewController { - - var detailViewController: DetailViewController? = nil - var objects = [Any]() - - - override func viewDidLoad() { - super.viewDidLoad() - // Do any additional setup after loading the view. - navigationItem.leftBarButtonItem = editButtonItem - - let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(insertNewObject(_:))) - navigationItem.rightBarButtonItem = addButton - if let split = splitViewController { - let controllers = split.viewControllers - detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController - } - } - - override func viewWillAppear(_ animated: Bool) { - clearsSelectionOnViewWillAppear = splitViewController!.isCollapsed - super.viewWillAppear(animated) - } - - @objc - func insertNewObject(_ sender: Any) { - objects.insert(NSDate(), at: 0) - let indexPath = IndexPath(row: 0, section: 0) - tableView.insertRows(at: [indexPath], with: .automatic) - } - - // MARK: - Segues - - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - if segue.identifier == "showDetail" { - if let indexPath = tableView.indexPathForSelectedRow { - let object = objects[indexPath.row] as! NSDate - let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController - controller.detailItem = object - controller.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem - controller.navigationItem.leftItemsSupplementBackButton = true - detailViewController = controller - } - } - } - - // MARK: - Table View - - override func numberOfSections(in tableView: UITableView) -> Int { - return 1 - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return objects.count - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) - let object = objects[indexPath.row] as! NSDate - cell.textLabel!.text = object.description - return cell - } - - override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { - // Return false if you do not want the specified item to be editable. - return true - } - - override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { - if editingStyle == .delete { - objects.remove(at: indexPath.row) - tableView.deleteRows(at: [indexPath], with: .fade) - } else if editingStyle == .insert { - // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view. - } - } - - -} - diff --git a/Wired iOS/ProfileViewController.swift b/Wired iOS/ProfileViewController.swift new file mode 100644 index 0000000..01dca97 --- /dev/null +++ b/Wired iOS/ProfileViewController.swift @@ -0,0 +1,92 @@ +// +// ProfileViewController.swift +// Wired iOS +// +// Created by Rafael Warnault on 01/04/2020. +// Copyright © 2020 Read-Write. All rights reserved. +// + +import UIKit + +extension Notification.Name { + static let userDidUpdateProfile = Notification.Name("userDidUpdateProfile") +} + + + +class ProfileViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate { + @IBOutlet var nickTextField: UITextField! + @IBOutlet var statusTextField: UITextField! + @IBOutlet var iconImageView: UIImageView! + + public var masterViewController:BookmarksViewController! + + override func viewDidLoad() { + super.viewDidLoad() + + if let image = UserDefaults.standard.image(forKey: "WSUserIcon") { + self.iconImageView.image = image + } + + if let nick = UserDefaults.standard.value(forKey: "WSUserNick") as? String { + self.nickTextField.text = nick + } + + if let status = UserDefaults.standard.value(forKey: "WSUserStatus") as? String { + self.statusTextField.text = status + } + } + + + // MARK: - + + func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { + picker.dismiss(animated: true) + + guard let image = info[.editedImage] as? UIImage else { + print("No image found") + return + } + + if let newImage = image.resize(withNewWidth: 64) { + self.iconImageView.image = newImage + } + } + + + + + // MARK: - + + @IBAction func changeIcon(_ sender: Any) { + let vc = UIImagePickerController() + vc.sourceType = .photoLibrary + vc.allowsEditing = true + vc.delegate = self + present(vc, animated: true) + } + + + @IBAction func cancel(_ sender: Any) { + self.dismiss(animated: true) { } + } + + @IBAction func ok(_ sender: Any) { + if let image = self.iconImageView.image { + UserDefaults.standard.set(image: image, forKey: "WSUserIcon") + } + + if let text = self.nickTextField.text { + UserDefaults.standard.set(text, forKey: "WSUserNick") + } + + if let text = self.statusTextField.text { + UserDefaults.standard.set(text, forKey: "WSUserStatus") + } + + self.dismiss(animated: true) { + NotificationCenter.default.post(name: .userDidUpdateProfile, object: nil) + } + } + +} diff --git a/Wired iOS/SceneDelegate.swift b/Wired iOS/SceneDelegate.swift index ef36d5f..8a35198 100644 --- a/Wired iOS/SceneDelegate.swift +++ b/Wired iOS/SceneDelegate.swift @@ -11,54 +11,54 @@ import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate, UISplitViewControllerDelegate { var window: UIWindow? - - - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. - // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. - // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). - guard let window = window else { return } - guard let splitViewController = window.rootViewController as? UISplitViewController else { return } - guard let navigationController = splitViewController.viewControllers.last as? UINavigationController else { return } - navigationController.topViewController?.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem - navigationController.topViewController?.navigationItem.leftItemsSupplementBackButton = true - splitViewController.delegate = self - } - - func sceneDidDisconnect(_ scene: UIScene) { - // Called as the scene is being released by the system. - // This occurs shortly after the scene enters the background, or when its session is discarded. - // Release any resources associated with this scene that can be re-created the next time the scene connects. - // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). - } - - func sceneDidBecomeActive(_ scene: UIScene) { - // Called when the scene has moved from an inactive state to an active state. - // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. - } - - func sceneWillResignActive(_ scene: UIScene) { - // Called when the scene will move from an active state to an inactive state. - // This may occur due to temporary interruptions (ex. an incoming phone call). - } - - func sceneWillEnterForeground(_ scene: UIScene) { - // Called as the scene transitions from the background to the foreground. - // Use this method to undo the changes made on entering the background. - } - - func sceneDidEnterBackground(_ scene: UIScene) { - // Called as the scene transitions from the foreground to the background. - // Use this method to save data, release shared resources, and store enough scene-specific state information - // to restore the scene back to its current state. - } +// +// +// func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { +// // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. +// // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. +// // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). +// guard let window = window else { return } +// guard let splitViewController = window.rootViewController as? UISplitViewController else { return } +// guard let navigationController = splitViewController.viewControllers.last as? UINavigationController else { return } +// navigationController.topViewController?.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem +// navigationController.topViewController?.navigationItem.leftItemsSupplementBackButton = true +// splitViewController.delegate = self +// } +// +// func sceneDidDisconnect(_ scene: UIScene) { +// // Called as the scene is being released by the system. +// // This occurs shortly after the scene enters the background, or when its session is discarded. +// // Release any resources associated with this scene that can be re-created the next time the scene connects. +// // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). +// } +// +// func sceneDidBecomeActive(_ scene: UIScene) { +// // Called when the scene has moved from an inactive state to an active state. +// // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. +// } +// +// func sceneWillResignActive(_ scene: UIScene) { +// // Called when the scene will move from an active state to an inactive state. +// // This may occur due to temporary interruptions (ex. an incoming phone call). +// } +// +// func sceneWillEnterForeground(_ scene: UIScene) { +// // Called as the scene transitions from the background to the foreground. +// // Use this method to undo the changes made on entering the background. +// } +// +// func sceneDidEnterBackground(_ scene: UIScene) { +// // Called as the scene transitions from the foreground to the background. +// // Use this method to save data, release shared resources, and store enough scene-specific state information +// // to restore the scene back to its current state. +// } // MARK: - Split view func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool { guard let secondaryAsNavController = secondaryViewController as? UINavigationController else { return false } - guard let topAsDetailController = secondaryAsNavController.topViewController as? DetailViewController else { return false } - if topAsDetailController.detailItem == nil { + guard let topAsDetailController = secondaryAsNavController.topViewController as? ChatViewController else { return false } + if topAsDetailController.connection == nil { // Return true to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded. return true } diff --git a/Wired iOS/ServerInfoViewController.swift b/Wired iOS/ServerInfoViewController.swift new file mode 100644 index 0000000..c77b203 --- /dev/null +++ b/Wired iOS/ServerInfoViewController.swift @@ -0,0 +1,151 @@ +// +// ServerInfoViewController.swift +// Wired iOS +// +// Created by Rafael Warnault on 01/04/2020. +// Copyright © 2020 Read-Write. All rights reserved. +// + +import UIKit +import WiredSwift_iOS +import MessageKit + +class ServerInfoViewController: UITableViewController { + var users:[UserInfo] = [] + + + // MARK: - + override func viewDidLoad() { + + super.viewDidLoad() + + updateView() + } + + + func updateView() { + self.tableView.reloadData() + + navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Disconnect", style: .done, target: self, action: #selector(disconnect)) + navigationItem.rightBarButtonItem?.tintColor = UIColor.red + } + + + // MARK: - + + var connection: Connection? { + didSet { + // Update the view. + if let c = self.connection { + if c.isConnected() { + self.navigationItem.title = self.connection?.serverInfo.serverName + + self.tableView.reloadData() + + updateView() + } + } + } + } + + + @objc func disconnect() { + if self.connection != nil && self.connection?.isConnected() == true { + let alertController = UIAlertController( + title: "Warning", + message: "Are you sure you want to disconnect?", + preferredStyle: .alert) + + alertController.addAction(UIAlertAction(title: "Cancel", style: .default)) + alertController.addAction(UIAlertAction(title: "OK", style: .default) { (action) in + self.connection?.disconnect() + + self.navigationController?.popToRootViewController(animated: true) + }) + + self.present(alertController, animated: true) { } + } + } + + + // MARK: - + + override func numberOfSections(in tableView: UITableView) -> Int { + if self.connection == nil || self.connection?.isConnected() == false { + return 0 + } + + return 3 + } + + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + if section == 0 { + return 2 + } + else if section == 1 { + return 2 + } + + return users.count + } + + + override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + if section == 0 { + return "Server Info" + } + else if section == 1 { + return "Connection" + } + + return "Connected Users" + } + + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: false) + } + + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) + + if indexPath.section == 0 { + if indexPath.row == 0 { + cell.textLabel!.lineBreakMode = .byWordWrapping + cell.textLabel!.numberOfLines = 0 + cell.textLabel!.text = self.connection!.serverInfo.serverDescription + } + else if indexPath.row == 1 { + cell.textLabel!.lineBreakMode = .byWordWrapping + cell.textLabel!.numberOfLines = 0 + cell.textLabel!.text = "\(self.connection!.serverInfo.applicationName!) \(self.connection!.serverInfo.applicationVersion!) on \(self.connection!.serverInfo.osName!) \(self.connection!.serverInfo.osVersion!) (\(self.connection!.serverInfo.arch!))" + } + } else if indexPath.section == 1 { + if indexPath.row == 0 { + cell.textLabel!.text = "Protocol \(self.connection!.socket.remoteName!) \(self.connection!.socket.remoteVersion!)" + } + else if indexPath.row == 1 { + cell.textLabel!.text = "Encryption \(P7Socket.CipherType.pretty(self.connection!.socket.cipherType))" + } + } else if indexPath.section == 2 { + let userCell = tableView.dequeueReusableCell(withIdentifier: "UserCell", for: indexPath) as? UserTableViewCell + + let user = users[indexPath.row] + userCell?.nickLabel!.text = user.nick + userCell?.statusLabel!.text = user.status + + if let base64ImageString = user.icon?.base64EncodedData() { + if let data = Data(base64Encoded: base64ImageString, options: .ignoreUnknownCharacters) { + let image = UIImage(data: data)?.resize(withNewWidth: 32.0) + userCell?.imageView?.image = image + } + } + + return userCell ?? cell + } + + return cell + } +} diff --git a/Wired iOS/UIImage+Resize.swift b/Wired iOS/UIImage+Resize.swift new file mode 100644 index 0000000..24294e3 --- /dev/null +++ b/Wired iOS/UIImage+Resize.swift @@ -0,0 +1,21 @@ +// +// UIImage+Resize.swift +// Wired iOS +// +// Created by Rafael Warnault on 01/04/2020. +// Copyright © 2020 Read-Write. All rights reserved. +// + +import UIKit + +extension UIImage { + public func resize(withNewWidth newWidth: CGFloat) -> UIImage? { + let scale = newWidth / self.size.width + let newHeight = self.size.height * scale + UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight)) + self.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight)) + let newImage = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + return newImage + } +} diff --git a/Wired iOS/UserTableViewCell.swift b/Wired iOS/UserTableViewCell.swift new file mode 100644 index 0000000..7cfa227 --- /dev/null +++ b/Wired iOS/UserTableViewCell.swift @@ -0,0 +1,27 @@ +// +// UserTableViewCell.swift +// Wired iOS +// +// Created by Rafael Warnault on 01/04/2020. +// Copyright © 2020 Read-Write. All rights reserved. +// + +import UIKit + +class UserTableViewCell: UITableViewCell { + @IBOutlet weak var nickLabel: UILabel! + @IBOutlet weak var statusLabel: UILabel! + @IBOutlet weak var iconImageView: UIImageView! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + // Configure the view for the selected state + } + +} diff --git a/Wired/Core Data/Bookmark+CoreDataClass.swift b/Wired/Core Data/Bookmark+CoreDataClass.swift index 499957d..ddd96c1 100644 --- a/Wired/Core Data/Bookmark+CoreDataClass.swift +++ b/Wired/Core Data/Bookmark+CoreDataClass.swift @@ -11,6 +11,12 @@ import Foundation import CoreData import KeychainAccess +#if os(iOS) +import WiredSwift_iOS +#else +import WiredSwift +#endif + @objc(Bookmark) public class Bookmark: NSManagedObject { diff --git a/WiredSwift.xcodeproj/project.pbxproj b/WiredSwift.xcodeproj/project.pbxproj index fe46d02..4fecc40 100644 --- a/WiredSwift.xcodeproj/project.pbxproj +++ b/WiredSwift.xcodeproj/project.pbxproj @@ -76,6 +76,8 @@ 4C5C1D242426812E00A751AA /* Message+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C5C1D202426812E00A751AA /* Message+CoreDataClass.swift */; }; 4C5C1D252426812E00A751AA /* Message+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C5C1D212426812E00A751AA /* Message+CoreDataProperties.swift */; }; 4C6A89E82405613A00780FEF /* FileManager+ResourceFork.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C6A89E72405613A00780FEF /* FileManager+ResourceFork.swift */; }; + 4C6B13DB2434E9FF00429775 /* WiredSwift_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CE2AA5B24336AF20072E0B3 /* WiredSwift_iOS.framework */; }; + 4C6B13DC2434E9FF00429775 /* WiredSwift_iOS.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4CE2AA5B24336AF20072E0B3 /* WiredSwift_iOS.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 4C74286222DCECE800D6E6F9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C74286122DCECE800D6E6F9 /* AppDelegate.swift */; }; 4C74286422DCECE800D6E6F9 /* ConnectController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C74286322DCECE800D6E6F9 /* ConnectController.swift */; }; 4C74286622DCECE900D6E6F9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4C74286522DCECE900D6E6F9 /* Assets.xcassets */; }; @@ -119,22 +121,36 @@ 4C75B9A92433717B00BE8857 /* AEXML in Frameworks */ = {isa = PBXBuildFile; productRef = 4C75B9A82433717B00BE8857 /* AEXML */; }; 4C75B9AB2433722900BE8857 /* AEXML in Frameworks */ = {isa = PBXBuildFile; productRef = 4C75B9AA2433722900BE8857 /* AEXML */; }; 4C75B9B3243374D900BE8857 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C75B9B2243374D900BE8857 /* AppDelegate.swift */; }; - 4C75B9B5243374D900BE8857 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C75B9B4243374D900BE8857 /* SceneDelegate.swift */; }; - 4C75B9B7243374D900BE8857 /* MasterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C75B9B6243374D900BE8857 /* MasterViewController.swift */; }; - 4C75B9B9243374D900BE8857 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C75B9B8243374D900BE8857 /* DetailViewController.swift */; }; + 4C75B9B7243374D900BE8857 /* BookmarksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C75B9B6243374D900BE8857 /* BookmarksViewController.swift */; }; + 4C75B9B9243374D900BE8857 /* ChatViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C75B9B8243374D900BE8857 /* ChatViewController.swift */; }; 4C75B9BC243374D900BE8857 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4C75B9BA243374D900BE8857 /* Main.storyboard */; }; 4C75B9BE243374DA00BE8857 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4C75B9BD243374DA00BE8857 /* Assets.xcassets */; }; 4C75B9C1243374DA00BE8857 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4C75B9BF243374DA00BE8857 /* LaunchScreen.storyboard */; }; 4C75B9CC243374DA00BE8857 /* Wired_iOSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C75B9CB243374DA00BE8857 /* Wired_iOSTests.swift */; }; 4C75B9D7243374DA00BE8857 /* Wired_iOSUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C75B9D6243374DA00BE8857 /* Wired_iOSUITests.swift */; }; - 4C75B9E2243375F900BE8857 /* WiredSwift_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CE2AA5B24336AF20072E0B3 /* WiredSwift_iOS.framework */; }; - 4C75B9E42433764700BE8857 /* WiredSwift_iOS.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4CE2AA5B24336AF20072E0B3 /* WiredSwift_iOS.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 4C75B9E5243379A500BE8857 /* wired.xml in Resources */ = {isa = PBXBuildFile; fileRef = 4CD0205C22DF11920008B36C /* wired.xml */; }; + 4C75BA272433928F00BE8857 /* Wired3.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 4CFB161823FC7D01000EE688 /* Wired3.xcdatamodeld */; }; + 4C75BA2C2433932C00BE8857 /* Bookmark+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFB161B23FC843C000EE688 /* Bookmark+CoreDataClass.swift */; }; + 4C75BA2D2433932C00BE8857 /* Bookmark+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFB161C23FC843C000EE688 /* Bookmark+CoreDataProperties.swift */; }; + 4C75BA362433938400BE8857 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 4C75BA352433938400BE8857 /* KeychainAccess */; }; + 4C75BA382433998600BE8857 /* BookmarkViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C75BA372433998600BE8857 /* BookmarkViewController.swift */; }; 4C7A45AB242937CA008F0FFE /* TimeAgo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7A45AA242937CA008F0FFE /* TimeAgo.swift */; }; 4C7D19222431DD91002897CB /* NSColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7D19212431DD91002897CB /* NSColor.swift */; }; 4C7D199824322B31002897CB /* MessageCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7D199724322B31002897CB /* MessageCellView.swift */; }; 4C8829E824254A0B00B4EF36 /* TabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C8829E724254A0B00B4EF36 /* TabViewController.swift */; }; 4C8829EA2425672700B4EF36 /* ConnectionWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C8829E92425672700B4EF36 /* ConnectionWindow.swift */; }; + 4C88747324347D4500A5D4A0 /* MainSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C88747224347D4500A5D4A0 /* MainSplitViewController.swift */; }; + 4C88747524347DC300A5D4A0 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C88747424347DC300A5D4A0 /* SceneDelegate.swift */; }; + 4C887477243480F200A5D4A0 /* ProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C887476243480F200A5D4A0 /* ProfileViewController.swift */; }; + 4C88747C243483A100A5D4A0 /* JGProgressHUD in Frameworks */ = {isa = PBXBuildFile; productRef = 4C88747B243483A100A5D4A0 /* JGProgressHUD */; }; + 4C88747E2434A10900A5D4A0 /* ServerInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C88747D2434A10900A5D4A0 /* ServerInfoViewController.swift */; }; + 4C8874802434A7FD00A5D4A0 /* UserTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C88747F2434A7FD00A5D4A0 /* UserTableViewCell.swift */; }; + 4C8874822434AB6F00A5D4A0 /* UIImage+Resize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C8874812434AB6F00A5D4A0 /* UIImage+Resize.swift */; }; + 4C8874842434B81800A5D4A0 /* BookmarkTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C8874832434B81800A5D4A0 /* BookmarkTableViewCell.swift */; }; + 4C8874872434DE9000A5D4A0 /* Reachability in Frameworks */ = {isa = PBXBuildFile; productRef = 4C8874862434DE9000A5D4A0 /* Reachability */; }; + 4C8874952434E98000A5D4A0 /* MessageKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C8874902434E6D700A5D4A0 /* MessageKit.framework */; }; + 4C8874962434E98000A5D4A0 /* MessageKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4C8874902434E6D700A5D4A0 /* MessageKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 4C8874982434E99700A5D4A0 /* CZlib in Frameworks */ = {isa = PBXBuildFile; productRef = 4C8874972434E99700A5D4A0 /* CZlib */; }; 4C93B2E7242F9BD500A956C3 /* BBCodeString.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C93B2E3242F9BD500A956C3 /* BBCodeString.m */; }; 4C93B2E8242F9BD500A956C3 /* NSMutableAttributedString+BBCodeString.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C93B2E6242F9BD500A956C3 /* NSMutableAttributedString+BBCodeString.m */; }; 4C93B2F2242F9CAE00A956C3 /* BBAttribute.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C93B2EA242F9CAD00A956C3 /* BBAttribute.m */; }; @@ -232,6 +248,13 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 4C6B13DD2434E9FF00429775 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C74285622DCECE800D6E6F9 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4CE2AA5A24336AF20072E0B3; + remoteInfo = WiredSwift_iOS; + }; 4C75B9C8243374DA00BE8857 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C74285622DCECE800D6E6F9 /* Project object */; @@ -246,6 +269,13 @@ remoteGlobalIDString = 4C75B9AF243374D900BE8857; remoteInfo = "Wired iOS"; }; + 4C88748D2434E6BB00A5D4A0 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C74285622DCECE800D6E6F9 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4CE2AA5A24336AF20072E0B3; + remoteInfo = WiredSwift_iOS; + }; 4C93B302242FE96200A956C3 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C74285622DCECE800D6E6F9 /* Project object */; @@ -284,14 +314,16 @@ name = "Copy Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; - 4C75B9E32433763F00BE8857 /* CopyFiles */ = { + 4C88748F2434E6BB00A5D4A0 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( - 4C75B9E42433764700BE8857 /* WiredSwift_iOS.framework in CopyFiles */, + 4C6B13DC2434E9FF00429775 /* WiredSwift_iOS.framework in Embed Frameworks */, + 4C8874962434E98000A5D4A0 /* MessageKit.framework in Embed Frameworks */, ); + name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; 4CD0205922DF04BD0008B36C /* Embed Frameworks */ = { @@ -385,9 +417,8 @@ 4C75B98C24336DDC00BE8857 /* Gzip.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Gzip.framework; path = Carthage/Build/iOS/Gzip.framework; sourceTree = SOURCE_ROOT; }; 4C75B9B0243374D900BE8857 /* Wired iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Wired iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 4C75B9B2243374D900BE8857 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 4C75B9B4243374D900BE8857 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; - 4C75B9B6243374D900BE8857 /* MasterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterViewController.swift; sourceTree = ""; }; - 4C75B9B8243374D900BE8857 /* DetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; }; + 4C75B9B6243374D900BE8857 /* BookmarksViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksViewController.swift; sourceTree = ""; }; + 4C75B9B8243374D900BE8857 /* ChatViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatViewController.swift; sourceTree = ""; }; 4C75B9BB243374D900BE8857 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 4C75B9BD243374DA00BE8857 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 4C75B9C0243374DA00BE8857 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; @@ -398,11 +429,20 @@ 4C75B9D2243374DA00BE8857 /* Wired iOSUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Wired iOSUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 4C75B9D6243374DA00BE8857 /* Wired_iOSUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Wired_iOSUITests.swift; sourceTree = ""; }; 4C75B9D8243374DA00BE8857 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 4C75BA372433998600BE8857 /* BookmarkViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkViewController.swift; sourceTree = ""; }; 4C7A45AA242937CA008F0FFE /* TimeAgo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeAgo.swift; sourceTree = ""; }; 4C7D19212431DD91002897CB /* NSColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSColor.swift; sourceTree = ""; }; 4C7D199724322B31002897CB /* MessageCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageCellView.swift; sourceTree = ""; }; 4C8829E724254A0B00B4EF36 /* TabViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabViewController.swift; sourceTree = ""; }; 4C8829E92425672700B4EF36 /* ConnectionWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionWindow.swift; sourceTree = ""; }; + 4C88747224347D4500A5D4A0 /* MainSplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainSplitViewController.swift; sourceTree = ""; }; + 4C88747424347DC300A5D4A0 /* SceneDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 4C887476243480F200A5D4A0 /* ProfileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewController.swift; sourceTree = ""; }; + 4C88747D2434A10900A5D4A0 /* ServerInfoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerInfoViewController.swift; sourceTree = ""; }; + 4C88747F2434A7FD00A5D4A0 /* UserTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserTableViewCell.swift; sourceTree = ""; }; + 4C8874812434AB6F00A5D4A0 /* UIImage+Resize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Resize.swift"; sourceTree = ""; }; + 4C8874832434B81800A5D4A0 /* BookmarkTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkTableViewCell.swift; sourceTree = ""; }; + 4C8874902434E6D700A5D4A0 /* MessageKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageKit.framework; path = Carthage/Build/iOS/MessageKit.framework; sourceTree = SOURCE_ROOT; }; 4C93B2E1242F9BD400A956C3 /* Wired-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Wired-Bridging-Header.h"; sourceTree = ""; }; 4C93B2E2242F9BD400A956C3 /* BBCodeStringDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BBCodeStringDelegate.h; sourceTree = ""; }; 4C93B2E3242F9BD500A956C3 /* BBCodeString.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BBCodeString.m; sourceTree = ""; }; @@ -497,7 +537,12 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 4C75B9E2243375F900BE8857 /* WiredSwift_iOS.framework in Frameworks */, + 4C88747C243483A100A5D4A0 /* JGProgressHUD in Frameworks */, + 4C8874982434E99700A5D4A0 /* CZlib in Frameworks */, + 4C8874952434E98000A5D4A0 /* MessageKit.framework in Frameworks */, + 4C75BA362433938400BE8857 /* KeychainAccess in Frameworks */, + 4C6B13DB2434E9FF00429775 /* WiredSwift_iOS.framework in Frameworks */, + 4C8874872434DE9000A5D4A0 /* Reachability in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -688,13 +733,21 @@ isa = PBXGroup; children = ( 4C75B9B2243374D900BE8857 /* AppDelegate.swift */, - 4C75B9B4243374D900BE8857 /* SceneDelegate.swift */, - 4C75B9B6243374D900BE8857 /* MasterViewController.swift */, - 4C75B9B8243374D900BE8857 /* DetailViewController.swift */, + 4C88747424347DC300A5D4A0 /* SceneDelegate.swift */, + 4C75B9B6243374D900BE8857 /* BookmarksViewController.swift */, + 4C75B9B8243374D900BE8857 /* ChatViewController.swift */, + 4C88747D2434A10900A5D4A0 /* ServerInfoViewController.swift */, + 4C88747224347D4500A5D4A0 /* MainSplitViewController.swift */, + 4C75BA372433998600BE8857 /* BookmarkViewController.swift */, + 4C887476243480F200A5D4A0 /* ProfileViewController.swift */, + 4C88747F2434A7FD00A5D4A0 /* UserTableViewCell.swift */, + 4C8874832434B81800A5D4A0 /* BookmarkTableViewCell.swift */, + 4C8874812434AB6F00A5D4A0 /* UIImage+Resize.swift */, 4C75B9BA243374D900BE8857 /* Main.storyboard */, 4C75B9BD243374DA00BE8857 /* Assets.xcassets */, 4C75B9BF243374DA00BE8857 /* LaunchScreen.storyboard */, 4C75B9C2243374DA00BE8857 /* Info.plist */, + 4C8874902434E6D700A5D4A0 /* MessageKit.framework */, ); path = "Wired iOS"; sourceTree = ""; @@ -1032,13 +1085,21 @@ 4C75B9AC243374D900BE8857 /* Sources */, 4C75B9AD243374D900BE8857 /* Frameworks */, 4C75B9AE243374D900BE8857 /* Resources */, - 4C75B9E32433763F00BE8857 /* CopyFiles */, + 4C88748F2434E6BB00A5D4A0 /* Embed Frameworks */, ); buildRules = ( ); dependencies = ( + 4C88748E2434E6BB00A5D4A0 /* PBXTargetDependency */, + 4C6B13DE2434E9FF00429775 /* PBXTargetDependency */, ); name = "Wired iOS"; + packageProductDependencies = ( + 4C75BA352433938400BE8857 /* KeychainAccess */, + 4C88747B243483A100A5D4A0 /* JGProgressHUD */, + 4C8874862434DE9000A5D4A0 /* Reachability */, + 4C8874972434E99700A5D4A0 /* CZlib */, + ); productName = "Wired iOS"; productReference = 4C75B9B0243374D900BE8857 /* Wired iOS.app */; productType = "com.apple.product-type.application"; @@ -1219,6 +1280,9 @@ 4C75B9A1243370C900BE8857 /* XCRemoteSwiftPackageReference "Socket.swift" */, 4C75B9A4243370F700BE8857 /* XCRemoteSwiftPackageReference "BlueRSA" */, 4C75B9A72433717B00BE8857 /* XCRemoteSwiftPackageReference "AEXML" */, + 4C75BA342433938400BE8857 /* XCRemoteSwiftPackageReference "KeychainAccess" */, + 4C8874782434836C00A5D4A0 /* XCRemoteSwiftPackageReference "JGProgressHUD" */, + 4C8874852434DE9000A5D4A0 /* XCRemoteSwiftPackageReference "Reachability" */, ); productRefGroup = 4C74285F22DCECE800D6E6F9 /* Products */; projectDirPath = ""; @@ -1415,10 +1479,20 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 4C88747E2434A10900A5D4A0 /* ServerInfoViewController.swift in Sources */, 4C75B9B3243374D900BE8857 /* AppDelegate.swift in Sources */, - 4C75B9B5243374D900BE8857 /* SceneDelegate.swift in Sources */, - 4C75B9B7243374D900BE8857 /* MasterViewController.swift in Sources */, - 4C75B9B9243374D900BE8857 /* DetailViewController.swift in Sources */, + 4C8874842434B81800A5D4A0 /* BookmarkTableViewCell.swift in Sources */, + 4C75BA272433928F00BE8857 /* Wired3.xcdatamodeld in Sources */, + 4C887477243480F200A5D4A0 /* ProfileViewController.swift in Sources */, + 4C8874802434A7FD00A5D4A0 /* UserTableViewCell.swift in Sources */, + 4C8874822434AB6F00A5D4A0 /* UIImage+Resize.swift in Sources */, + 4C88747524347DC300A5D4A0 /* SceneDelegate.swift in Sources */, + 4C75BA2C2433932C00BE8857 /* Bookmark+CoreDataClass.swift in Sources */, + 4C75BA2D2433932C00BE8857 /* Bookmark+CoreDataProperties.swift in Sources */, + 4C75BA382433998600BE8857 /* BookmarkViewController.swift in Sources */, + 4C75B9B7243374D900BE8857 /* BookmarksViewController.swift in Sources */, + 4C75B9B9243374D900BE8857 /* ChatViewController.swift in Sources */, + 4C88747324347D4500A5D4A0 /* MainSplitViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1527,6 +1601,11 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 4C6B13DE2434E9FF00429775 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 4CE2AA5A24336AF20072E0B3 /* WiredSwift_iOS */; + targetProxy = 4C6B13DD2434E9FF00429775 /* PBXContainerItemProxy */; + }; 4C75B9C9243374DA00BE8857 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 4C75B9AF243374D900BE8857 /* Wired iOS */; @@ -1537,6 +1616,11 @@ target = 4C75B9AF243374D900BE8857 /* Wired iOS */; targetProxy = 4C75B9D3243374DA00BE8857 /* PBXContainerItemProxy */; }; + 4C88748E2434E6BB00A5D4A0 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 4CE2AA5A24336AF20072E0B3 /* WiredSwift_iOS */; + targetProxy = 4C88748D2434E6BB00A5D4A0 /* PBXContainerItemProxy */; + }; 4C93B303242FE96200A956C3 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 4CD0204C22DF04BD0008B36C /* WiredSwift */; @@ -1821,8 +1905,12 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = JSVJHJ78QE; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/iOS", + ); INFOPLIST_FILE = "Wired iOS/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 13.2; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1841,8 +1929,12 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = JSVJHJ78QE; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/iOS", + ); INFOPLIST_FILE = "Wired iOS/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 13.2; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -2088,7 +2180,7 @@ ); INFOPLIST_FILE = WiredSwift_iOS/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 13.2; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -2122,7 +2214,7 @@ ); INFOPLIST_FILE = WiredSwift_iOS/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 13.2; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -2312,6 +2404,30 @@ minimumVersion = 4.5.0; }; }; + 4C75BA342433938400BE8857 /* XCRemoteSwiftPackageReference "KeychainAccess" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/kishikawakatsumi/KeychainAccess"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 4.1.0; + }; + }; + 4C8874782434836C00A5D4A0 /* XCRemoteSwiftPackageReference "JGProgressHUD" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/JonasGessner/JGProgressHUD"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 2.1.0; + }; + }; + 4C8874852434DE9000A5D4A0 /* XCRemoteSwiftPackageReference "Reachability" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/ashleymills/Reachability.swift"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 5.0.0; + }; + }; 4CF673762404191600A8EDC2 /* XCRemoteSwiftPackageReference "CZlib" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/IBM-Swift/CZlib.git"; @@ -2353,6 +2469,26 @@ package = 4C75B9A72433717B00BE8857 /* XCRemoteSwiftPackageReference "AEXML" */; productName = AEXML; }; + 4C75BA352433938400BE8857 /* KeychainAccess */ = { + isa = XCSwiftPackageProductDependency; + package = 4C75BA342433938400BE8857 /* XCRemoteSwiftPackageReference "KeychainAccess" */; + productName = KeychainAccess; + }; + 4C88747B243483A100A5D4A0 /* JGProgressHUD */ = { + isa = XCSwiftPackageProductDependency; + package = 4C8874782434836C00A5D4A0 /* XCRemoteSwiftPackageReference "JGProgressHUD" */; + productName = JGProgressHUD; + }; + 4C8874862434DE9000A5D4A0 /* Reachability */ = { + isa = XCSwiftPackageProductDependency; + package = 4C8874852434DE9000A5D4A0 /* XCRemoteSwiftPackageReference "Reachability" */; + productName = Reachability; + }; + 4C8874972434E99700A5D4A0 /* CZlib */ = { + isa = XCSwiftPackageProductDependency; + package = 4CF673762404191600A8EDC2 /* XCRemoteSwiftPackageReference "CZlib" */; + productName = CZlib; + }; 4CF673772404191E00A8EDC2 /* CZlib */ = { isa = XCSwiftPackageProductDependency; package = 4CF673762404191600A8EDC2 /* XCRemoteSwiftPackageReference "CZlib" */; diff --git a/WiredSwift.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/WiredSwift.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 0b8b506..daa5411 100644 --- a/WiredSwift.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/WiredSwift.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -37,6 +37,33 @@ "version": "0.1.2" } }, + { + "package": "JGProgressHUD", + "repositoryURL": "https://github.com/JonasGessner/JGProgressHUD", + "state": { + "branch": null, + "revision": "08d130dd614a743f813286f096804c43a6ffa3f6", + "version": "2.1.0" + } + }, + { + "package": "KeychainAccess", + "repositoryURL": "https://github.com/kishikawakatsumi/KeychainAccess", + "state": { + "branch": null, + "revision": "b920ad7df3c73189dcdd4aa05c540849b2010dbf", + "version": "4.1.0" + } + }, + { + "package": "Reachability", + "repositoryURL": "https://github.com/ashleymills/Reachability.swift", + "state": { + "branch": null, + "revision": "98e968e7b6c1318fb61df23e347bc319761e8acb", + "version": "5.0.0" + } + }, { "package": "SocketSwift", "repositoryURL": "https://github.com/BiAtoms/Socket.swift.git", diff --git a/WiredSwift.xcodeproj/xcshareddata/xcschemes/Wired iOS.xcscheme b/WiredSwift.xcodeproj/xcshareddata/xcschemes/Wired iOS.xcscheme index 169e026..cefa0ef 100644 --- a/WiredSwift.xcodeproj/xcshareddata/xcschemes/Wired iOS.xcscheme +++ b/WiredSwift.xcodeproj/xcshareddata/xcschemes/Wired iOS.xcscheme @@ -51,7 +51,7 @@