From 091af0844a6923e65cdaa293cdc53cdfa7e04038 Mon Sep 17 00:00:00 2001 From: Charles Magahern Date: Sat, 13 May 2017 00:40:03 -0700 Subject: [PATCH 1/2] Conversion to Swift3 --- XIONControlPanel.xcodeproj/project.pbxproj | 14 ++- .../Application/AppDelegate.swift | 20 ++-- .../Controllers/MainViewController.swift | 68 +++++------ .../Controllers/SwitchesViewController.swift | 113 +++++++++--------- .../VisualizationViewController.swift | 87 +++++++------- XIONControlPanel/Controllers/WemoServer.swift | 110 ++++++++--------- XIONControlPanel/Models/WemoDevice.swift | 20 ++-- .../Utilities/NSErrorAdditions.swift | 23 ++-- .../Utilities/NSURLAdditions.swift | 20 ++-- XIONControlPanel/Utilities/Semaphore.swift | 19 +-- .../Utilities/StandardError.swift | 8 +- .../Views/ConnectionStatusView.swift | 42 +++---- XIONControlPanel/Views/HeaderView.swift | 24 ++-- .../Views/SwitchIndicatorView.swift | 34 +++--- XIONControlPanel/Views/WemoCellView.swift | 56 ++++----- XIONControlPanel/Views/XIONLogoView.swift | 20 ++-- 16 files changed, 353 insertions(+), 325 deletions(-) diff --git a/XIONControlPanel.xcodeproj/project.pbxproj b/XIONControlPanel.xcodeproj/project.pbxproj index 41a92c9..f5e5097 100644 --- a/XIONControlPanel.xcodeproj/project.pbxproj +++ b/XIONControlPanel.xcodeproj/project.pbxproj @@ -247,7 +247,8 @@ TargetAttributes = { 0C3CAEA31C3350C800B856AD = { CreatedOnToolsVersion = 7.2; - DevelopmentTeam = FZ6BMA5HA9; + DevelopmentTeam = 64S2YWUDC5; + LastSwiftMigration = 0810; }; }; }; @@ -422,11 +423,15 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; INFOPLIST_FILE = "$(SRCROOT)/XIONControlPanel/SupportingFiles/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks/Swift", + ); PRODUCT_BUNDLE_IDENTIFIER = com.xionsf.XIONControlPanel; PRODUCT_NAME = XION; PROVISIONING_PROFILE = ""; SWIFT_OBJC_BRIDGING_HEADER = "XIONControlPanel/SupportingFiles/XIONControlPanel-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -440,10 +445,15 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; INFOPLIST_FILE = "$(SRCROOT)/XIONControlPanel/SupportingFiles/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks/Swift", + ); PRODUCT_BUNDLE_IDENTIFIER = com.xionsf.XIONControlPanel; PRODUCT_NAME = XION; PROVISIONING_PROFILE = ""; SWIFT_OBJC_BRIDGING_HEADER = "XIONControlPanel/SupportingFiles/XIONControlPanel-Bridging-Header.h"; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; diff --git a/XIONControlPanel/Application/AppDelegate.swift b/XIONControlPanel/Application/AppDelegate.swift index b53ee20..28bf888 100644 --- a/XIONControlPanel/Application/AppDelegate.swift +++ b/XIONControlPanel/Application/AppDelegate.swift @@ -14,35 +14,35 @@ class AppDelegate: UIResponder, UIApplicationDelegate var window: UIWindow? var mainViewController: MainViewController = MainViewController() - func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { - application.statusBarHidden = true + application.isStatusBarHidden = true - self.window = UIWindow(frame: UIScreen.mainScreen().bounds) + self.window = UIWindow(frame: UIScreen.main.bounds) self.window?.rootViewController = self.mainViewController self.window?.makeKeyAndVisible() return true } - func applicationDidBecomeActive(application: UIApplication) + func applicationDidBecomeActive(_ application: UIApplication) { self.mainViewController.viewDidAppear(false) } - func applicationDidEnterBackground(application: UIApplication) + func applicationDidEnterBackground(_ application: UIApplication) { self.mainViewController.viewDidDisappear(false) } - func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask + func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { - var mask: UIInterfaceOrientationMask = .Portrait + var mask: UIInterfaceOrientationMask = .portrait - if (UIDevice.currentDevice().userInterfaceIdiom == .Phone) { - mask = UIInterfaceOrientationMask.Portrait + if (UIDevice.current.userInterfaceIdiom == .phone) { + mask = UIInterfaceOrientationMask.portrait } else { - mask = UIInterfaceOrientationMask.All + mask = UIInterfaceOrientationMask.all } return mask diff --git a/XIONControlPanel/Controllers/MainViewController.swift b/XIONControlPanel/Controllers/MainViewController.swift index 7864b09..8e39103 100644 --- a/XIONControlPanel/Controllers/MainViewController.swift +++ b/XIONControlPanel/Controllers/MainViewController.swift @@ -10,15 +10,15 @@ import UIKit class MainViewController: UIViewController, SwitchesViewControllerDelegate { - private var _server: WemoServer - private var _visualizationController: VisualizationViewController = VisualizationViewController() - private var _switchesController: SwitchesViewController = SwitchesViewController() - private var _headerView: HeaderView = HeaderView() - private var _updateDevices: Bool = false + fileprivate var _server: WemoServer + fileprivate var _visualizationController: VisualizationViewController = VisualizationViewController() + fileprivate var _switchesController: SwitchesViewController = SwitchesViewController() + fileprivate var _headerView: HeaderView = HeaderView() + fileprivate var _updateDevices: Bool = false - override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { - let url = NSURL(string: "http://midna.xionsf.com:5000") + let url = URL(string: "http://midna.xionsf.com:5000") _server = WemoServer(url!) super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) @@ -35,7 +35,7 @@ class MainViewController: UIViewController, SwitchesViewControllerDelegate { super.viewDidLoad() - self.view.backgroundColor = UIColor.blackColor() + self.view.backgroundColor = UIColor.black self.addChildViewController(_visualizationController) self.view.addSubview(_visualizationController.view) @@ -46,7 +46,7 @@ class MainViewController: UIViewController, SwitchesViewControllerDelegate self.view.addSubview(_headerView) - _updateConnectivityStatus(.Disconnected) + _updateConnectivityStatus(.disconnected) } override func viewDidLayoutSubviews() @@ -64,7 +64,7 @@ class MainViewController: UIViewController, SwitchesViewControllerDelegate ) let bodyBounds = CGRect( x: 0.0, - y: CGRectGetMaxY(headerBounds), + y: headerBounds.maxY, width: bounds.size.width, height: bounds.size.height - headerBounds.size.height ) @@ -81,8 +81,8 @@ class MainViewController: UIViewController, SwitchesViewControllerDelegate var switchesOriginX: CGFloat = 0.0 var switchesWidth: CGFloat = 0.0 - if (horizontalSizeClass == .Regular) { - switchesOriginX = CGRectGetMaxX(visualizationFrame) + if (horizontalSizeClass == .regular) { + switchesOriginX = visualizationFrame.maxX switchesWidth = bodyBounds.size.width - visualizationFrame.size.width } else { switchesOriginX = 0.0 @@ -98,32 +98,32 @@ class MainViewController: UIViewController, SwitchesViewControllerDelegate _switchesController.view.frame = switchesControllerFrame } - override func viewDidAppear(animated: Bool) + override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) _headerView.xionLogoView.beginAnimating() if (!_server.connected) { - _updateConnectivityStatus(.Connecting) - _server.connect { (error: NSError?) -> Void in + _updateConnectivityStatus(.connecting) + _server.connect { (error: Error?) -> Void in if (error == nil) { self._reloadDevices() self._startUpdatingDevices() } else { - self._updateConnectivityStatus(.Error) + self._updateConnectivityStatus(.error) } } } } - override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { - super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator) + super.viewWillTransition(to: size, with: coordinator) _updateSizeClassPresentation() } - override func prefersStatusBarHidden() -> Bool + override var prefersStatusBarHidden : Bool { return true } @@ -141,12 +141,12 @@ class MainViewController: UIViewController, SwitchesViewControllerDelegate // MARK: SwitchesViewControllerDelegate - func switchesViewControllerDidToggleDevices(controller: SwitchesViewController, devices: [WemoDevice]) + func switchesViewControllerDidToggleDevices(_ controller: SwitchesViewController, devices: [WemoDevice]) { _updateVisualization(true) for device in devices { - _server.toggleDevice(device, state: device.state, completion: { (error: NSError?) -> Void in }) + _server.toggleDevice(device, state: device.state, completion: { (error: Error?) -> Void in }) } } @@ -155,18 +155,18 @@ class MainViewController: UIViewController, SwitchesViewControllerDelegate internal func _updateSizeClassPresentation() { let horizontalSizeClass = self.traitCollection.horizontalSizeClass - if (horizontalSizeClass == .Regular) { - _visualizationController.view.hidden = false + if (horizontalSizeClass == .regular) { + _visualizationController.view.isHidden = false } else { - _visualizationController.view.hidden = true + _visualizationController.view.isHidden = true } } - internal func _updateVisualization(animated: Bool) + internal func _updateVisualization(_ animated: Bool) { var activatedDevicesCount = 0 for device in self.devices { - if (device.state == .On) { + if (device.state == .on) { activatedDevicesCount += 1 } } @@ -177,9 +177,9 @@ class MainViewController: UIViewController, SwitchesViewControllerDelegate } } - internal func _updateConnectivityStatus(status: ConnectionStatus) + internal func _updateConnectivityStatus(_ status: ConnectionStatus) { - dispatch_async(dispatch_get_main_queue()) { () -> Void in + DispatchQueue.main.async { () -> Void in self._headerView.connectionStatusView.connectivityStatus = status self._headerView.setNeedsLayout() self._visualizationController.connectionStatus = status @@ -188,14 +188,14 @@ class MainViewController: UIViewController, SwitchesViewControllerDelegate internal func _reloadDevices() { - _server.fetchDevices({ (devices: [WemoDevice], error: NSError?) -> Void in - dispatch_async(dispatch_get_main_queue()) { () -> Void in + _server.fetchDevices({ (devices: [WemoDevice], error: Error?) -> Void in + DispatchQueue.main.async { () -> Void in if (error == nil) { self.devices = devices - self._updateConnectivityStatus(.Connected) + self._updateConnectivityStatus(.connected) } else { self.devices = [] - self._updateConnectivityStatus(.Error) + self._updateConnectivityStatus(.error) } } }) @@ -205,8 +205,8 @@ class MainViewController: UIViewController, SwitchesViewControllerDelegate { _updateDevices = true - let interval = dispatch_time(DISPATCH_TIME_NOW, Int64(10 * Double(NSEC_PER_SEC))) - dispatch_after(interval, dispatch_get_main_queue()) { () -> Void in + let interval = DispatchTime.now() + Double(Int64(10 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC) + DispatchQueue.main.asyncAfter(deadline: interval) { () -> Void in if (self._updateDevices) { self._reloadDevices() self._startUpdatingDevices() diff --git a/XIONControlPanel/Controllers/SwitchesViewController.swift b/XIONControlPanel/Controllers/SwitchesViewController.swift index 9a20595..15a579c 100644 --- a/XIONControlPanel/Controllers/SwitchesViewController.swift +++ b/XIONControlPanel/Controllers/SwitchesViewController.swift @@ -12,12 +12,12 @@ import UIKit protocol SwitchesViewControllerDelegate: class { - func switchesViewControllerDidToggleDevices(controller: SwitchesViewController, devices: [WemoDevice]) + func switchesViewControllerDidToggleDevices(_ controller: SwitchesViewController, devices: [WemoDevice]) } extension SwitchesViewControllerDelegate { - func switchesViewControllerDidToggleDevices(controller: SwitchesViewController, devices: [WemoDevice]) {} + func switchesViewControllerDidToggleDevices(_ controller: SwitchesViewController, devices: [WemoDevice]) {} } class SwitchesViewController: UIViewController, @@ -25,25 +25,25 @@ class SwitchesViewController: UIViewController, UICollectionViewDelegateFlowLayout { weak var delegate: SwitchesViewControllerDelegate? - private var _collectionView: UICollectionView = UICollectionView(frame: CGRectZero, + fileprivate var _collectionView: UICollectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: UICollectionViewFlowLayout()) - private var _currentDevicesHash: Int = 0 + fileprivate var _currentDevicesHash: Int = 0 - static private let collectionViewDeviceSwitchCellReuseIdentifier = "DeviceSwitchReuseID" - static private let collectionViewActionCellReuseIdentifier = "ActionCellReuseID" - static private let collectionViewCellsSpacing: CGFloat = 5.0 + static fileprivate let collectionViewDeviceSwitchCellReuseIdentifier = "DeviceSwitchReuseID" + static fileprivate let collectionViewActionCellReuseIdentifier = "ActionCellReuseID" + static fileprivate let collectionViewCellsSpacing: CGFloat = 5.0 - private enum ActionCell: Int + fileprivate enum ActionCell: Int { - case AllOn - case AllOff + case allOn + case allOff func name() -> String { switch self { - case .AllOn: + case .allOn: return "All On" - case .AllOff: + case .allOff: return "All Off" } } @@ -62,15 +62,15 @@ class SwitchesViewController: UIViewController, let deviceCellReuseID = SwitchesViewController.collectionViewDeviceSwitchCellReuseIdentifier let actionCellReuseID = SwitchesViewController.collectionViewActionCellReuseIdentifier let layout = _collectionView.collectionViewLayout as! UICollectionViewFlowLayout - layout.scrollDirection = .Vertical + layout.scrollDirection = .vertical layout.minimumInteritemSpacing = SwitchesViewController.collectionViewCellsSpacing layout.minimumLineSpacing = SwitchesViewController.collectionViewCellsSpacing - _collectionView.backgroundColor = UIColor.blackColor() + _collectionView.backgroundColor = UIColor.black _collectionView.delegate = self _collectionView.dataSource = self - _collectionView.registerClass(WemoDeviceCellView.self, forCellWithReuseIdentifier: deviceCellReuseID) - _collectionView.registerClass(WemoActionCellView.self, forCellWithReuseIdentifier: actionCellReuseID) + _collectionView.register(WemoDeviceCellView.self, forCellWithReuseIdentifier: deviceCellReuseID) + _collectionView.register(WemoActionCellView.self, forCellWithReuseIdentifier: actionCellReuseID) self.view.addSubview(_collectionView) self.devices = [] @@ -91,36 +91,36 @@ class SwitchesViewController: UIViewController, didSet { // sort devices by name - self.devices.sortInPlace({ (d1: WemoDevice, d2: WemoDevice) -> Bool in - return (d1.name.compare(d2.name) == .OrderedAscending) + self.devices.sort(by: { (d1: WemoDevice, d2: WemoDevice) -> Bool in + return (d1.name.compare(d2.name) == .orderedAscending) }) - let hash = self.devices.reduce(0, combine: {$0 ^ $1.hashValue}) + let hash = self.devices.reduce(0, {$0 ^ $1.hashValue}) if (hash != _currentDevicesHash) { let previousSet = NSOrderedSet(array: oldValue) let newSet = NSOrderedSet(array: self.devices) - var insertedIndexPaths: [NSIndexPath] = [] - var updatedIndexPaths: [NSIndexPath] = [] - var deletedIndexPaths: [NSIndexPath] = [] + var insertedIndexPaths: [IndexPath] = [] + var updatedIndexPaths: [IndexPath] = [] + var deletedIndexPaths: [IndexPath] = [] // if we have devices now and we didn't before, or vice versa, // we need to update the action cells if ((oldValue.count == 0 && self.devices.count != 0) || (self.devices.count == 0 && oldValue.count != 0)) { for actionCellIdx in 0 ..< ActionCell.count { - let actionCellIndexPath = NSIndexPath(forItem: actionCellIdx, inSection: 0) + let actionCellIndexPath = IndexPath(item: actionCellIdx, section: 0) updatedIndexPaths.append(actionCellIndexPath) } } // find deletes and updates - for (idx, device) in previousSet.enumerate() { + for (idx, device) in previousSet.enumerated() { let itemIndex = idx + ActionCell.count - let curIndexPath = NSIndexPath(forItem: itemIndex, inSection: 0) + let curIndexPath = IndexPath(item: itemIndex, section: 0) - if (!newSet.containsObject(device)) { + if (!newSet.contains(device)) { deletedIndexPaths.append(curIndexPath) } else if (idx < newSet.count) { - let deviceInNewSet = newSet.objectAtIndex(idx) as! WemoDevice + let deviceInNewSet = newSet.object(at: idx) as! WemoDevice if (deviceInNewSet != (device as! WemoDevice)) { updatedIndexPaths.append(curIndexPath) } @@ -128,19 +128,19 @@ class SwitchesViewController: UIViewController, } // find insertions - for (idx, device) in newSet.enumerate() { - if (!previousSet.containsObject(device)) { + for (idx, device) in newSet.enumerated() { + if (!previousSet.contains(device)) { let itemIndex = idx + ActionCell.count - let insertedIndexPath = NSIndexPath(forItem: itemIndex, inSection: 0) + let insertedIndexPath = IndexPath(item: itemIndex, section: 0) insertedIndexPaths.append(insertedIndexPath) } } UIView.performWithoutAnimation { () -> Void in self._collectionView.performBatchUpdates({ () -> Void in - self._collectionView.deleteItemsAtIndexPaths(deletedIndexPaths) - self._collectionView.reloadItemsAtIndexPaths(updatedIndexPaths) - self._collectionView.insertItemsAtIndexPaths(insertedIndexPaths) + self._collectionView.deleteItems(at: deletedIndexPaths) + self._collectionView.reloadItems(at: updatedIndexPaths) + self._collectionView.insertItems(at: insertedIndexPaths) }, completion: nil) } @@ -151,46 +151,47 @@ class SwitchesViewController: UIViewController, // MARK: UICollectionView - func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return self.devices.count + ActionCell.count } - func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { if (indexPath.item < ActionCell.count) { let reuseID = SwitchesViewController.collectionViewActionCellReuseIdentifier - let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseID, forIndexPath: indexPath) as! WemoActionCellView - cell.textLabel.text = ActionCell(rawValue: indexPath.item)?.name().uppercaseString + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseID, for: indexPath) as! WemoActionCellView + cell.textLabel.text = ActionCell(rawValue: indexPath.item)?.name().uppercased() cell.enabled = (self.devices.count > 0) return cell } else { let reuseID = SwitchesViewController.collectionViewDeviceSwitchCellReuseIdentifier - let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseID, forIndexPath: indexPath) as! WemoDeviceCellView + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseID, for: indexPath) as! WemoDeviceCellView let device = _deviceAtIndexPath(indexPath) cell.deviceName = device.name - cell.toggled = (device.state == .On) + cell.toggled = (device.state == .on) cell.ordinal = indexPath.item - ActionCell.count + 1 return cell } } - func collectionView(collectionView: UICollectionView, + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, - sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize + sizeForItemAt indexPath: IndexPath) -> CGSize { let spacing = SwitchesViewController.collectionViewCellsSpacing let bounds = collectionView.bounds var cellsPerRow: CGFloat = 0.0 switch (self.traitCollection.horizontalSizeClass) { - case .Regular, .Compact where (bounds.size.width >= 400.0): + case .regular where (bounds.size.width >= 400.0), + .compact where (bounds.size.width >= 400.0): cellsPerRow = 3.0 break - case .Compact: + case .compact: cellsPerRow = 2.0 default: cellsPerRow = 2.0 @@ -204,18 +205,18 @@ class SwitchesViewController: UIViewController, } } - func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { if (indexPath.item < ActionCell.count) { let tappedActionCell = ActionCell(rawValue: indexPath.item) - var currentDelay: NSTimeInterval = 0.0 + var currentDelay: TimeInterval = 0.0 - for i in ActionCell.count ..< collectionView.numberOfItemsInSection(indexPath.section) { - if let cell = collectionView.cellForItemAtIndexPath(NSIndexPath(forItem: i, inSection: indexPath.section)) as? WemoDeviceCellView { - let animOptions = UIViewAnimationOptions([.AllowUserInteraction]) + for i in ActionCell.count ..< collectionView.numberOfItems(inSection: indexPath.section) { + if let cell = collectionView.cellForItem(at: IndexPath(item: i, section: indexPath.section)) as? WemoDeviceCellView { + let animOptions = UIViewAnimationOptions([.allowUserInteraction]) - UIView.animateWithDuration(0.3, delay: currentDelay, options: animOptions, animations: { - cell.toggled = (tappedActionCell == .AllOn) + UIView.animate(withDuration: 0.3, delay: currentDelay, options: animOptions, animations: { + cell.toggled = (tappedActionCell == .allOn) }, completion: nil) currentDelay += 0.05 @@ -223,22 +224,22 @@ class SwitchesViewController: UIViewController, } for device in self.devices { - device.state = (tappedActionCell == .AllOn ? .On : .Off) + device.state = (tappedActionCell == .allOn ? .on : .off) } self.delegate?.switchesViewControllerDidToggleDevices(self, devices: self.devices) } else { - let cell = collectionView.cellForItemAtIndexPath(indexPath) as! WemoDeviceCellView + let cell = collectionView.cellForItem(at: indexPath) as! WemoDeviceCellView cell.toggled = !cell.toggled let device = _deviceAtIndexPath(indexPath) - device.state = (cell.toggled ? .On : .Off) + device.state = (cell.toggled ? .on : .off) self.delegate?.switchesViewControllerDidToggleDevices(self, devices: [device]) } } - func collectionView(collectionView: UICollectionView, shouldHighlightItemAtIndexPath indexPath: NSIndexPath) -> Bool + func collectionView(_ collectionView: UICollectionView, shouldHighlightItemAt indexPath: IndexPath) -> Bool { if (indexPath.item < ActionCell.count) { return (self.devices.count > 0) @@ -247,7 +248,7 @@ class SwitchesViewController: UIViewController, } } - func collectionView(collectionView: UICollectionView, shouldSelectItemAtIndexPath indexPath: NSIndexPath) -> Bool + func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool { if (indexPath.item < ActionCell.count) { return (self.devices.count > 0) @@ -258,7 +259,7 @@ class SwitchesViewController: UIViewController, // MARK: Internal - internal func _deviceAtIndexPath(indexPath: NSIndexPath) -> WemoDevice + internal func _deviceAtIndexPath(_ indexPath: IndexPath) -> WemoDevice { let deviceIdx = indexPath.item - ActionCell.count let device = self.devices[deviceIdx] diff --git a/XIONControlPanel/Controllers/VisualizationViewController.swift b/XIONControlPanel/Controllers/VisualizationViewController.swift index b16dfcd..b94a489 100644 --- a/XIONControlPanel/Controllers/VisualizationViewController.swift +++ b/XIONControlPanel/Controllers/VisualizationViewController.swift @@ -11,31 +11,32 @@ import Foundation import GLKit import SceneKit import UIKit +import SceneKit -let π = CGFloat(M_PI) +let π = CGFloat(Double.pi) class VisualizationViewController: UIViewController { - private var _scene: SCNScene = SCNScene() - private var _sceneView: SCNView? - private var _cameraNode: SCNNode = SCNNode() - private var _lightNode: SCNNode = SCNNode() - private var _cubletsNode: SCNNode = SCNNode() - private var _cublets: [SCNNode] = [] - private var _percentActivated: Float = 0.0 + fileprivate var _scene: SCNScene = SCNScene() + fileprivate var _sceneView: SCNView? + fileprivate var _cameraNode: SCNNode = SCNNode() + fileprivate var _lightNode: SCNNode = SCNNode() + fileprivate var _cubletsNode: SCNNode = SCNNode() + fileprivate var _cublets: [SCNNode] = [] + fileprivate var _percentActivated: Float = 0.0 - static private let cubletsDimensions = 5 - static private let cubletsSize = 1.0 - static private let cubletsSpacing = 2.0 - static private let rotationAnimationKey = "RotationAnimation" + static fileprivate let cubletsDimensions = 5 + static fileprivate let cubletsSize = 1.0 + static fileprivate let cubletsSpacing = 2.0 + static fileprivate let rotationAnimationKey = "RotationAnimation" // MARK: Overrides override func loadView() { - let opts = [SCNPreferredRenderingAPIKey : SCNRenderingAPI.OpenGLES2.rawValue] - let view = SCNView(frame: UIScreen.mainScreen().bounds, options: opts) - view.backgroundColor = UIColor.blackColor() + let opts = [SCNView.Option.preferredRenderingAPI.rawValue : SCNRenderingAPI.openGLES2] + let view = SCNView(frame: UIScreen.main.bounds, options: opts) + view.backgroundColor = UIColor.black view.scene = _scene view.allowsCameraControl = false @@ -55,13 +56,13 @@ class VisualizationViewController: UIViewController _beginModelResetTimer() } - override func viewDidAppear(animated: Bool) + override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) _sceneView?.play(nil) } - override func viewDidDisappear(animated: Bool) + override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) _sceneView?.stop(nil) @@ -69,17 +70,17 @@ class VisualizationViewController: UIViewController // MARK: API - var connectionStatus: ConnectionStatus = .Disconnected + var connectionStatus: ConnectionStatus = .disconnected { didSet { switch (self.connectionStatus) { - case .Disconnected, .Connecting, .Error: - _cubletsNode.paused = true + case .disconnected, .connecting, .error: + _cubletsNode.isPaused = true _lightNode.light?.color = UIColor(white: 0.3, alpha: 1.0) - case .Connected: - _cubletsNode.paused = false - _lightNode.light?.color = UIColor.whiteColor() + case .connected: + _cubletsNode.isPaused = false + _lightNode.light?.color = UIColor.white } } } @@ -97,7 +98,7 @@ class VisualizationViewController: UIViewController } } - func setPercentActivated(percentage: Float, animated: Bool) + func setPercentActivated(_ percentage: Float, animated: Bool) { let cubletsCount = _cublets.count let cubletsToActivate = UInt(percentage * Float(cubletsCount)) @@ -124,8 +125,8 @@ class VisualizationViewController: UIViewController let rotCoeff = CGFloat(arc4random() % 2 == 0 ? -1.0 : 1.0) let rotAngle = CGFloat(rotCoeff * π / 4.0) - let rotAction = SCNAction.rotateByAngle(rotAngle, aroundAxis: rotAxis, duration: 0.8) - rotAction.timingMode = .Linear + let rotAction = SCNAction.rotate(by: rotAngle, around: rotAxis, duration: 0.8) + rotAction.timingMode = .linear rotAction.timingFunction = { (t: Float) -> Float in return min(((log10(4.0 * (t + 0.03)) + 1.0) / 1.5), 1.0) } @@ -134,7 +135,7 @@ class VisualizationViewController: UIViewController // smooth transition let longTermAnimKey = VisualizationViewController.rotationAnimationKey let newLongTermRotAction = _createLongTermRotationAnimation((rotCoeff * 2.0 * π), rotAxis) - _cubletsNode.removeActionForKey(longTermAnimKey) + _cubletsNode.removeAction(forKey: longTermAnimKey) let actionSeq = SCNAction.sequence([rotAction, newLongTermRotAction]) _cubletsNode.runAction(actionSeq, forKey: longTermAnimKey) @@ -166,8 +167,8 @@ class VisualizationViewController: UIViewController internal func _setupLights() { let light = SCNLight() - light.type = SCNLightTypeOmni - light.color = UIColor.whiteColor() + light.type = SCNLight.LightType.omni + light.color = UIColor.white _lightNode = SCNNode() _lightNode.light = light @@ -178,7 +179,7 @@ class VisualizationViewController: UIViewController internal func _setupModel() { - _cubletsNode.enumerateChildNodesUsingBlock { $0.0.removeFromParentNode() } + _cubletsNode.enumerateChildNodes { $0.0.removeFromParentNode() } _cublets.removeAll() let sz = Float(VisualizationViewController.cubletsSize) @@ -191,7 +192,7 @@ class VisualizationViewController: UIViewController // setup material and geometry. each node needs its own material for the activation effect. let geom = SCNBox(width: CGFloat(sz), height: CGFloat(sz), length: CGFloat(sz), chamferRadius: 0.0) let material = SCNMaterial() - material.diffuse.contents = UIColor.whiteColor() + material.diffuse.contents = UIColor.white material.transparency = 0.75 // generate nodes for each cublet @@ -216,7 +217,7 @@ class VisualizationViewController: UIViewController } _cubletsNode.position = SCNVector3Zero - if (_cubletsNode.parentNode == nil) { + if (_cubletsNode.parent == nil) { _scene.rootNode.addChildNode(_cubletsNode) } } @@ -232,8 +233,8 @@ class VisualizationViewController: UIViewController internal func _setupEffects() { - let techniqueURL = NSBundle.mainBundle().URLForResource("CubletsTechnique", withExtension: "plist") - let techniqueDict = NSDictionary(contentsOfURL: techniqueURL!) as! [String : AnyObject] + let techniqueURL = Bundle.main.url(forResource: "CubletsTechnique", withExtension: "plist") + let techniqueDict = NSDictionary(contentsOf: techniqueURL!) as! [String : AnyObject] let technique = SCNTechnique(dictionary: techniqueDict) _sceneView?.technique = technique @@ -244,8 +245,8 @@ class VisualizationViewController: UIViewController /* since this visualization is running all the time, trigonometric functions begin malfunctioning at very large numbers. just reload the model every 24 hours so we don't have to see it */ - let reloadModelTime = dispatch_time(DISPATCH_TIME_NOW, Int64(60 * 60 * 24 * NSEC_PER_SEC)) - dispatch_after(reloadModelTime, dispatch_get_main_queue()) { [weak self] in + let reloadModelTime = DispatchTime.now() + Double(Int64(60 * 60 * 24 * NSEC_PER_SEC)) / Double(NSEC_PER_SEC) + DispatchQueue.main.asyncAfter(deadline: reloadModelTime) { [weak self] in if let strongSelf = self { strongSelf._cubletsNode.removeFromParentNode() strongSelf._cubletsNode = SCNNode() @@ -263,25 +264,25 @@ class VisualizationViewController: UIViewController } } - internal func _setCubletActivated(cublet: SCNNode, activated: Bool) + internal func _setCubletActivated(_ cublet: SCNNode, activated: Bool) { let material = cublet.geometry?.firstMaterial - material?.diffuse.contents = (activated ? UIColor.redColor() : UIColor.whiteColor()) + material?.diffuse.contents = (activated ? UIColor.red : UIColor.white) } - internal func _setAnimationSpeed(speed: CGFloat) + internal func _setAnimationSpeed(_ speed: CGFloat) { let key = VisualizationViewController.rotationAnimationKey - if let action = _cubletsNode.actionForKey(key) { - _cubletsNode.removeActionForKey(key) + if let action = _cubletsNode.action(forKey: key) { + _cubletsNode.removeAction(forKey: key) action.speed = speed _cubletsNode.runAction(action, forKey: key) } } - internal func _createLongTermRotationAnimation(rotAngle: CGFloat, _ rotAxis: SCNVector3) -> SCNAction + internal func _createLongTermRotationAnimation(_ rotAngle: CGFloat, _ rotAxis: SCNVector3) -> SCNAction { - return SCNAction.repeatActionForever(SCNAction.rotateByAngle(rotAngle, aroundAxis: rotAxis, duration: 40.0)) + return SCNAction.repeatForever(SCNAction.rotate(by: rotAngle, around: rotAxis, duration: 40.0)) } } diff --git a/XIONControlPanel/Controllers/WemoServer.swift b/XIONControlPanel/Controllers/WemoServer.swift index 0bdad5c..1d3b319 100644 --- a/XIONControlPanel/Controllers/WemoServer.swift +++ b/XIONControlPanel/Controllers/WemoServer.swift @@ -10,40 +10,46 @@ import Foundation enum ConnectionStatus { - case Disconnected - case Connecting - case Connected - case Error + case disconnected + case connecting + case connected + case error +} + +enum ConnectionError : Error +{ + case unknown + case serverUnavailable } class WemoServer { - private(set) var baseURL: NSURL - private(set) var connected: Bool = false + fileprivate(set) var baseURL: URL + fileprivate(set) var connected: Bool = false - private var _urlSession: NSURLSession - private var _errorStream: StandardErrorOutputStream = StandardErrorOutputStream() - private var _operationQueue: NSOperationQueue = NSOperationQueue() + fileprivate var _urlSession: URLSession + fileprivate var _errorStream: StandardErrorOutputStream = StandardErrorOutputStream() + fileprivate var _operationQueue: OperationQueue = OperationQueue() - init(_ url: NSURL) + init(_ url: URL) { self.baseURL = url - let config = NSURLSessionConfiguration.defaultSessionConfiguration() - _urlSession = NSURLSession(configuration: config) + let config = URLSessionConfiguration.default + _urlSession = URLSession(configuration: config) _operationQueue.maxConcurrentOperationCount = 1 } - func connect(completion: (NSError?) -> Void) + func connect(_ completion: @escaping (Error?) -> Void) { if (!self.connected) { let op = ConnectOperation(baseURL: self.baseURL, session: _urlSession) weak var weakOp = op op.completionBlock = { guard let strongOp = weakOp else { completion(nil) ; return } - if (strongOp.error != nil) { - self._logError("Error connecting to server", error: strongOp.error!) + if let error = strongOp.error { + self._logError("Error connecting to server", error: error) } else { self.connected = true } @@ -56,68 +62,68 @@ class WemoServer } } - func disconnect(completion: (NSError?) -> Void) + func disconnect(_ completion: (Error?) -> Void) { self.connected = false completion(nil) } - func fetchDevices(completion: ([WemoDevice], NSError?) -> Void) + func fetchDevices(_ completion: @escaping ([WemoDevice], Error?) -> Void) { if (self.connected) { let op = FetchDevicesOperation(baseURL: self.baseURL, session: _urlSession) weak var weakOp = op op.completionBlock = { guard let strongOp = weakOp else { completion([], nil) ; return } - if (strongOp.error != nil) { - self._logError("Error fetching devices", error: strongOp.error!) + if let error = strongOp.error { + self._logError("Error fetching devices", error: error) } completion(strongOp.devices, strongOp.error) } _operationQueue.addOperation(op) } else { - let err = NSError.xionError(.ConnectionError) + let err = ConnectionError.serverUnavailable completion([], err) } } - func toggleDevice(device: WemoDevice, state: WemoDevice.State, completion: (NSError?) -> Void) + func toggleDevice(_ device: WemoDevice, state: WemoDevice.State, completion: @escaping (Error?) -> Void) { if (self.connected) { let op = ToggleDeviceOperation(baseURL: self.baseURL, session: _urlSession, device: device, state: state) weak var weakOp = op op.completionBlock = { guard let strongOp = weakOp else { completion(nil) ; return } - if (strongOp.error != nil) { - self._logError("Error toggling device", error: strongOp.error!) + if let error = strongOp.error { + self._logError("Error toggling device", error: error) } completion(strongOp.error) } _operationQueue.addOperation(op) } else { - let err = NSError.xionError(.ConnectionError) + let err = ConnectionError.serverUnavailable completion(err) } } // MARK: Internal - internal func _logError(description: String, error: NSError) + internal func _logError(_ description: String, error: Error) { - print("ERROR: \(description) \(error)", toStream: &_errorStream) + print("ERROR: \(description) \(error)", to: &_errorStream) } } -internal class WemoOperation : NSOperation +internal class WemoOperation : Operation { - var baseURL: NSURL - var session: NSURLSession + var baseURL: URL + var session: URLSession - internal(set) var error: NSError? + internal(set) var error: Error? - init(baseURL: NSURL, session: NSURLSession) + init(baseURL: URL, session: URLSession) { self.baseURL = baseURL self.session = session @@ -129,16 +135,14 @@ internal class ConnectOperation : WemoOperation override func main() { let semaphore = Semaphore(value: 0) - let url = self.baseURL.URLByAppendingPathComponent("api/environment") - let request = NSMutableURLRequest(URL: url) - request.HTTPMethod = "POST" + let url = self.baseURL.appendingPathComponent("api/environment") + var request = URLRequest(url: url) + request.httpMethod = "POST" - let task = self.session.dataTaskWithRequest(request) { (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in - if (error != nil) { - self.error = NSError.xionError(.ConnectionError, underlying: error!) - } + let task = self.session.dataTask(with: request, completionHandler: { (data: Data?, response: URLResponse?, error: Error?) -> Void in + self.error = error semaphore.signal() - } + }) task.resume() semaphore.wait() } @@ -151,24 +155,24 @@ internal class FetchDevicesOperation : WemoOperation override func main() { let semaphore = Semaphore(value: 0) - let url = self.baseURL.URLByAppendingPathComponent("api/environment") - let task = self.session.dataTaskWithURL(url) { (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in + let url = self.baseURL.appendingPathComponent("api/environment") + let task = self.session.dataTask(with: url, completionHandler: { (data: Data?, response: URLResponse?, error: NSError?) -> Void in if (data != nil) { self.devices = self._parseDevices(data!) } else { - self.error = NSError.xionError(.ConnectionError, underlying: error) + self.error = NSError.xionError(.connectionError, underlying: error) } semaphore.signal() - } + } as! (Data?, URLResponse?, Error?) -> Void) task.resume() semaphore.wait() } - internal func _parseDevices(data: NSData) -> [WemoDevice] + internal func _parseDevices(_ data: Data) -> [WemoDevice] { var devices: [WemoDevice] = [] - if let responseDict = (try? NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as? NSDictionary) { + if let responseDict = (try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions()) as? NSDictionary) { for responseObj in (responseDict?.allValues)! { if let responseDict = responseObj as? NSDictionary { let device = WemoDevice(responseDict) @@ -186,7 +190,7 @@ internal class ToggleDeviceOperation : WemoOperation var device: WemoDevice var state: WemoDevice.State - init(baseURL: NSURL, session: NSURLSession, device: WemoDevice, state: WemoDevice.State) + init(baseURL: URL, session: URLSession, device: WemoDevice, state: WemoDevice.State) { self.device = device self.state = state @@ -196,15 +200,13 @@ internal class ToggleDeviceOperation : WemoOperation override func main() { let semaphore = Semaphore(value: 0) - let stateArg = (self.state == .On ? "on" : "off") - let url = self.baseURL.URLByAppendingPathComponent("api/device/\(self.device.name)").URLByAppendingRequestParameters(["state" : stateArg]) - let request = NSMutableURLRequest(URL: url!) - request.HTTPMethod = "POST" + let stateArg = (self.state == .on ? "on" : "off") + let url = self.baseURL.appendingPathComponent("api/device/\(self.device.name)").URLByAppendingRequestParameters(["state" : stateArg]) + var request = URLRequest(url: url!) + request.httpMethod = "POST" - let task = self.session.dataTaskWithRequest(request) { (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in - if (error != nil) { - self.error = NSError.xionError(.ConnectionError, underlying: error) - } + let task = self.session.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in + self.error = error semaphore.signal() } task.resume() diff --git a/XIONControlPanel/Models/WemoDevice.swift b/XIONControlPanel/Models/WemoDevice.swift index 584b9f3..760bac6 100644 --- a/XIONControlPanel/Models/WemoDevice.swift +++ b/XIONControlPanel/Models/WemoDevice.swift @@ -12,20 +12,20 @@ class WemoDevice: Hashable { enum State { - case Off - case On + case off + case on } - enum Type + enum DeviceType { - case Switch + case `switch` } var name: String = "" var host: String = "" var model: String = "" - var state: State = .Off - var type: Type = .Switch + var state: State = .off + var type: DeviceType = .switch var serial: String = "" init() @@ -46,13 +46,13 @@ class WemoDevice: Hashable } if let state = dict["state"] as? NSNumber { - switch (state.integerValue) { + switch (state.intValue) { case 0: - self.state = .Off + self.state = .off case 1: - self.state = .On + self.state = .on default: - self.state = .Off + self.state = .off } } diff --git a/XIONControlPanel/Utilities/NSErrorAdditions.swift b/XIONControlPanel/Utilities/NSErrorAdditions.swift index 6c155c8..2e98447 100644 --- a/XIONControlPanel/Utilities/NSErrorAdditions.swift +++ b/XIONControlPanel/Utilities/NSErrorAdditions.swift @@ -10,22 +10,31 @@ import Foundation enum XIONErrorCode: Int { - case Unknown - case ConnectionError + case unknown + case connectionError +} + +struct XIONError : Error +{ + enum ErrorCode + { + case unknown + case connectionError + } } extension NSError { - private static let XIONErrorDomain = "com.xionsf.controlpanel" + fileprivate static let XIONErrorDomain = "com.xionsf.controlpanel" - class func xionError(code: XIONErrorCode) -> NSError + class func xionError(_ code: XIONErrorCode) -> NSError { return self.xionError(code, userInfo: nil) } - class func xionError(code: XIONErrorCode, underlying: NSError?) -> NSError + class func xionError(_ code: XIONErrorCode, underlying: NSError?) -> NSError { - var userInfo: [NSObject : AnyObject]? = nil + var userInfo: [AnyHashable: Any]? = nil if (underlying != nil) { userInfo = [ NSUnderlyingErrorKey : underlying! @@ -35,7 +44,7 @@ extension NSError return self.xionError(code, userInfo: userInfo) } - class func xionError(code: XIONErrorCode, userInfo: [NSObject : AnyObject]?) -> NSError + class func xionError(_ code: XIONErrorCode, userInfo: [AnyHashable: Any]?) -> NSError { return NSError(domain: XIONErrorDomain, code: code.rawValue, userInfo: userInfo) } diff --git a/XIONControlPanel/Utilities/NSURLAdditions.swift b/XIONControlPanel/Utilities/NSURLAdditions.swift index 48d903b..bbf2b94 100644 --- a/XIONControlPanel/Utilities/NSURLAdditions.swift +++ b/XIONControlPanel/Utilities/NSURLAdditions.swift @@ -7,22 +7,22 @@ import Foundation -extension NSURL +extension URL { var requestParameters: [String : String]? { get { - let urlComponents = self.absoluteString.componentsSeparatedByString("/") + let urlComponents = self.absoluteString.components(separatedBy: "/") let paramsString = urlComponents[urlComponents.count - 1] - let parameterComponents = paramsString.componentsSeparatedByCharactersInSet(NSCharacterSet(charactersInString: "&?")) + let parameterComponents = paramsString.components(separatedBy: CharacterSet(charactersIn: "&?")) var dict: Dictionary = Dictionary() for paramPair in parameterComponents { - let kvPair = paramPair.componentsSeparatedByString("=") + let kvPair = paramPair.components(separatedBy: "=") if (kvPair.count == 2 && kvPair[0].characters.count > 0) { - let key = kvPair[0].stringByRemovingPercentEncoding! - let value = kvPair[1].stringByRemovingPercentEncoding! + let key = kvPair[0].removingPercentEncoding! + let value = kvPair[1].removingPercentEncoding! dict[key] = value } } @@ -31,7 +31,7 @@ extension NSURL } } - func URLByAppendingRequestParameters(params: [String : String]) -> NSURL? + func URLByAppendingRequestParameters(_ params: [String : String]) -> URL? { var paramsString = "" @@ -43,14 +43,14 @@ extension NSURL delim = "&" } - let keyParam = key.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet()) - let valueParam = value.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet()) + let keyParam = key.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) + let valueParam = value.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) paramsString += "\(delim)\(keyParam!)=\(valueParam!)" } var absoluteString = self.absoluteString absoluteString += paramsString - return NSURL(string: absoluteString) + return URL(string: absoluteString) } } diff --git a/XIONControlPanel/Utilities/Semaphore.swift b/XIONControlPanel/Utilities/Semaphore.swift index 578c626..699917b 100644 --- a/XIONControlPanel/Utilities/Semaphore.swift +++ b/XIONControlPanel/Utilities/Semaphore.swift @@ -10,11 +10,11 @@ import Foundation class Semaphore { - private var _semaphore: dispatch_semaphore_t + fileprivate var _semaphore: DispatchSemaphore init(value: Int) { - _semaphore = dispatch_semaphore_create(value) + _semaphore = DispatchSemaphore(value: value) } func wait() @@ -22,18 +22,21 @@ class Semaphore self.wait(nil) } - func wait(untilDate: NSDate?) + func wait(_ untilDate: Date?) { - var time: dispatch_time_t = DISPATCH_TIME_FOREVER - if (untilDate != nil) { - time = UInt64(untilDate!.timeIntervalSinceNow) * NSEC_PER_SEC + var time: DispatchTime = DispatchTime.distantFuture + if let untilDate = untilDate { + time = .now() + .milliseconds(Int(untilDate.timeIntervalSinceNow * 1000)) } - dispatch_semaphore_wait(_semaphore, time) + let result = _semaphore.wait(timeout: time) + if (result != .success) { + print("semaphore timed out") + } } func signal() { - dispatch_semaphore_signal(_semaphore) + _semaphore.signal() } } diff --git a/XIONControlPanel/Utilities/StandardError.swift b/XIONControlPanel/Utilities/StandardError.swift index 7a6f735..224b234 100644 --- a/XIONControlPanel/Utilities/StandardError.swift +++ b/XIONControlPanel/Utilities/StandardError.swift @@ -8,11 +8,11 @@ import Foundation -class StandardErrorOutputStream: OutputStreamType +class StandardErrorOutputStream: TextOutputStream { - func write(string: String) + func write(_ string: String) { - let stderr = NSFileHandle.fileHandleWithStandardError() - stderr.writeData(string.dataUsingEncoding(NSUTF8StringEncoding)!) + let stderr = FileHandle.standardError + stderr.write(string.data(using: String.Encoding.utf8)!) } } diff --git a/XIONControlPanel/Views/ConnectionStatusView.swift b/XIONControlPanel/Views/ConnectionStatusView.swift index a2e0514..b2f89f8 100644 --- a/XIONControlPanel/Views/ConnectionStatusView.swift +++ b/XIONControlPanel/Views/ConnectionStatusView.swift @@ -10,25 +10,25 @@ import UIKit class ConnectionStatusView: UIView { - private var _connectivityStatus: ConnectionStatus = .Disconnected - private var _japaneseLabel: UILabel = UILabel() - private var _englishLabel: UILabel = UILabel() + fileprivate var _connectivityStatus: ConnectionStatus = .disconnected + fileprivate var _japaneseLabel: UILabel = UILabel() + fileprivate var _englishLabel: UILabel = UILabel() - static private let labelsVMargin: CGFloat = 5.0 + static fileprivate let labelsVMargin: CGFloat = 5.0 override init(frame: CGRect) { super.init(frame: frame) _japaneseLabel.font = UIFont(name: "Orbitron-Medium", size: 24.0) - _japaneseLabel.textColor = UIColor.whiteColor() + _japaneseLabel.textColor = UIColor.white self.addSubview(_japaneseLabel) _englishLabel.font = UIFont(name: "Orbitron-Medium", size: 16.0) - _englishLabel.textColor = UIColor.whiteColor() + _englishLabel.textColor = UIColor.white self.addSubview(_englishLabel) - self.connectivityStatus = .Disconnected + self.connectivityStatus = .disconnected } required init?(coder aDecoder: NSCoder) @@ -38,7 +38,7 @@ class ConnectionStatusView: UIView // MARK: Overrides - override func sizeThatFits(size: CGSize) -> CGSize + override func sizeThatFits(_ size: CGSize) -> CGSize { let labelsVMargin = ConnectionStatusView.labelsVMargin let jpLabelSize = _japaneseLabel.sizeThatFits(size) @@ -67,7 +67,7 @@ class ConnectionStatusView: UIView _englishLabel.frame = CGRect( x: rint(bounds.size.width / 2.0 - enLabelSize.width / 2.0), - y: CGRectGetMaxY(_japaneseLabel.frame) + labelsVMargin, + y: _japaneseLabel.frame.maxY + labelsVMargin, width: enLabelSize.width, height: enLabelSize.height ) @@ -87,30 +87,30 @@ class ConnectionStatusView: UIView _connectivityStatus = newStatus switch (_connectivityStatus) { - case .Disconnected: + case .disconnected: _japaneseLabel.text = "非直結" - _japaneseLabel.textColor = UIColor.redColor() + _japaneseLabel.textColor = UIColor.red _englishLabel.text = "offline" - _englishLabel.textColor = UIColor.redColor() - case .Connecting: + _englishLabel.textColor = UIColor.red + case .connecting: _japaneseLabel.text = "接続中" - _japaneseLabel.textColor = UIColor.yellowColor() + _japaneseLabel.textColor = UIColor.yellow _englishLabel.text = "connecting..." - _englishLabel.textColor = UIColor.yellowColor() - case .Connected: + _englishLabel.textColor = UIColor.yellow + case .connected: _japaneseLabel.text = "直結" - _japaneseLabel.textColor = UIColor.greenColor() + _japaneseLabel.textColor = UIColor.green _englishLabel.text = "online" - _englishLabel.textColor = UIColor.greenColor() - case .Error: + _englishLabel.textColor = UIColor.green + case .error: _japaneseLabel.text = "過失" - _japaneseLabel.textColor = UIColor.redColor() + _japaneseLabel.textColor = UIColor.red _englishLabel.text = "error" - _englishLabel.textColor = UIColor.redColor() + _englishLabel.textColor = UIColor.red } self.setNeedsLayout() diff --git a/XIONControlPanel/Views/HeaderView.swift b/XIONControlPanel/Views/HeaderView.swift index 72faa11..3d4588f 100644 --- a/XIONControlPanel/Views/HeaderView.swift +++ b/XIONControlPanel/Views/HeaderView.swift @@ -15,24 +15,24 @@ class HeaderView: UIView var xionLogoView: XIONLogoView = XIONLogoView() var connectionStatusView: ConnectionStatusView = ConnectionStatusView() - private var _xionTitleLabel: UILabel = UILabel() - private var _xionJapaneseLabel: UILabel = UILabel() + fileprivate var _xionTitleLabel: UILabel = UILabel() + fileprivate var _xionJapaneseLabel: UILabel = UILabel() override init(frame: CGRect) { super.init(frame: frame) - self.backgroundColor = UIColor.blackColor() + self.backgroundColor = UIColor.black self.addSubview(self.xionLogoView) _xionTitleLabel.font = UIFont(name: "Orbitron-Medium", size: 16.0) _xionTitleLabel.text = "XION arcade system control panel" - _xionTitleLabel.textColor = UIColor.whiteColor() + _xionTitleLabel.textColor = UIColor.white self.addSubview(_xionTitleLabel) _xionJapaneseLabel.font = UIFont(name: "Orbitron-Medium", size: 12.0) _xionJapaneseLabel.text = "ザイーオンゲームセンターのシステム制御プログラム" - _xionJapaneseLabel.textColor = UIColor.whiteColor() + _xionJapaneseLabel.textColor = UIColor.white self.addSubview(_xionJapaneseLabel) self.addSubview(self.connectionStatusView) @@ -59,12 +59,12 @@ class HeaderView: UIView ) self.xionLogoView.frame = logoFrame - if (self.traitCollection.horizontalSizeClass == .Compact) { - _xionTitleLabel.hidden = true - _xionJapaneseLabel.hidden = true + if (self.traitCollection.horizontalSizeClass == .compact) { + _xionTitleLabel.isHidden = true + _xionJapaneseLabel.isHidden = true } else { - _xionTitleLabel.hidden = false - _xionJapaneseLabel.hidden = false + _xionTitleLabel.isHidden = false + _xionJapaneseLabel.isHidden = false let titleJPVerticalMargin: CGFloat = 5.0 let titleLabelSize = _xionTitleLabel.sizeThatFits(bounds.size) @@ -72,7 +72,7 @@ class HeaderView: UIView let totalLabelsHeight = titleLabelSize.height + titleJPVerticalMargin + jpLabelSize.height let titleFrame = CGRect( - x: CGRectGetMaxX(logoFrame) + hpadding * 2.0, + x: logoFrame.maxX + hpadding * 2.0, y: rint(bounds.size.height / 2.0 - totalLabelsHeight / 2.0), width: titleLabelSize.width, height: titleLabelSize.height @@ -81,7 +81,7 @@ class HeaderView: UIView let jpTitleFrame = CGRect( x: titleFrame.origin.x, - y: CGRectGetMaxY(titleFrame) + titleJPVerticalMargin, + y: titleFrame.maxY + titleJPVerticalMargin, width: jpLabelSize.width, height: jpLabelSize.height + 2.0 ) diff --git a/XIONControlPanel/Views/SwitchIndicatorView.swift b/XIONControlPanel/Views/SwitchIndicatorView.swift index 426c72c..c70f342 100644 --- a/XIONControlPanel/Views/SwitchIndicatorView.swift +++ b/XIONControlPanel/Views/SwitchIndicatorView.swift @@ -10,22 +10,22 @@ import UIKit class SwitchIndicatorView: UIView { - private var _status: Bool = false - private var _foregroundColor: UIColor = UIColor.whiteColor() - private var _outerCircleLayer: CAShapeLayer = CAShapeLayer() - private var _offSymbolLayer: CAShapeLayer = CAShapeLayer() - private var _onSymbolLayer: CAShapeLayer = CAShapeLayer() + fileprivate var _status: Bool = false + fileprivate var _foregroundColor: UIColor = UIColor.white + fileprivate var _outerCircleLayer: CAShapeLayer = CAShapeLayer() + fileprivate var _offSymbolLayer: CAShapeLayer = CAShapeLayer() + fileprivate var _onSymbolLayer: CAShapeLayer = CAShapeLayer() - static private var lineWidth: CGFloat = 2.0 + static fileprivate var lineWidth: CGFloat = 2.0 override init(frame: CGRect) { super.init(frame: frame) - _outerCircleLayer.fillColor = UIColor.clearColor().CGColor + _outerCircleLayer.fillColor = UIColor.clear.cgColor _outerCircleLayer.lineWidth = SwitchIndicatorView.lineWidth - _offSymbolLayer.fillColor = UIColor.clearColor().CGColor + _offSymbolLayer.fillColor = UIColor.clear.cgColor _offSymbolLayer.lineWidth = SwitchIndicatorView.lineWidth self.layer.addSublayer(_outerCircleLayer) @@ -33,7 +33,7 @@ class SwitchIndicatorView: UIView self.layer.addSublayer(_onSymbolLayer) self.status = false - self.foregroundColor = UIColor.whiteColor() + self.foregroundColor = UIColor.white } required init?(coder aDecoder: NSCoder) @@ -52,7 +52,7 @@ class SwitchIndicatorView: UIView _offSymbolLayer.frame = bounds _onSymbolLayer.frame = bounds - _outerCircleLayer.path = CGPathCreateWithEllipseInRect(bounds, nil) + _outerCircleLayer.path = CGPath(ellipseIn: bounds, transform: nil) let innerSize = CGSize(width: rint(bounds.size.width / 2.0), height: rint(bounds.size.height / 2.0)) let innerBounds = CGRect( @@ -61,7 +61,7 @@ class SwitchIndicatorView: UIView width: innerSize.width, height: innerSize.height ) - _offSymbolLayer.path = CGPathCreateWithEllipseInRect(innerBounds, nil) + _offSymbolLayer.path = CGPath(ellipseIn: innerBounds, transform: nil) let onSymbolSize = CGSize(width: lineWidth, height: innerSize.height) let onSymbolRect = CGRect( @@ -70,7 +70,7 @@ class SwitchIndicatorView: UIView width: onSymbolSize.width, height: onSymbolSize.height ) - _onSymbolLayer.path = CGPathCreateWithRect(onSymbolRect, nil) + _onSymbolLayer.path = CGPath(rect: onSymbolRect, transform: nil) } // MARK: API @@ -85,8 +85,8 @@ class SwitchIndicatorView: UIView set(status) { _status = status - _offSymbolLayer.hidden = _status - _onSymbolLayer.hidden = !_status + _offSymbolLayer.isHidden = _status + _onSymbolLayer.isHidden = !_status } } @@ -100,9 +100,9 @@ class SwitchIndicatorView: UIView set(color) { _foregroundColor = color - _outerCircleLayer.strokeColor = _foregroundColor.CGColor - _offSymbolLayer.strokeColor = _foregroundColor.CGColor - _onSymbolLayer.fillColor = _foregroundColor.CGColor + _outerCircleLayer.strokeColor = _foregroundColor.cgColor + _offSymbolLayer.strokeColor = _foregroundColor.cgColor + _onSymbolLayer.fillColor = _foregroundColor.cgColor } } } diff --git a/XIONControlPanel/Views/WemoCellView.swift b/XIONControlPanel/Views/WemoCellView.swift index 537613e..dac03f8 100644 --- a/XIONControlPanel/Views/WemoCellView.swift +++ b/XIONControlPanel/Views/WemoCellView.swift @@ -8,12 +8,12 @@ import UIKit -public class WemoCellView: UICollectionViewCell +open class WemoCellView: UICollectionViewCell { - private var _selectionOverlayView: UIView = UIView() + fileprivate var _selectionOverlayView: UIView = UIView() - static private var disabledBackgroundColor = UIColor(white: 0.2, alpha: 1.0) - static private var enabledBackgroundColor = UIColor(red: 0.0, green: 0.8, blue: 0.0, alpha: 1.0) + static fileprivate var disabledBackgroundColor = UIColor(white: 0.2, alpha: 1.0) + static fileprivate var enabledBackgroundColor = UIColor(red: 0.0, green: 0.8, blue: 0.0, alpha: 1.0) override init(frame: CGRect) { @@ -21,7 +21,7 @@ public class WemoCellView: UICollectionViewCell self.contentView.backgroundColor = WemoCellView.disabledBackgroundColor - _selectionOverlayView.backgroundColor = UIColor.clearColor() + _selectionOverlayView.backgroundColor = UIColor.clear self.contentView.addSubview(_selectionOverlayView) } @@ -32,7 +32,7 @@ public class WemoCellView: UICollectionViewCell // MARK: Overrides - override public func layoutSubviews() + override open func layoutSubviews() { super.layoutSubviews() @@ -40,29 +40,30 @@ public class WemoCellView: UICollectionViewCell _selectionOverlayView.frame = bounds } - override public var highlighted: Bool { + override open var isHighlighted: Bool { didSet { - if (self.highlighted) { + if (self.isHighlighted) { _selectionOverlayView.backgroundColor = UIColor(white: 0.8, alpha: 1.0) } else { - let animOptions = UIViewAnimationOptions([.AllowUserInteraction]) - UIView.animateWithDuration(1.0, delay: 0.0, options: animOptions, animations: { - self._selectionOverlayView.backgroundColor = UIColor.clearColor() + let animOptions = UIViewAnimationOptions([.allowUserInteraction]) + UIView.animate(withDuration: 1.0, delay: 0.0, options: animOptions, animations: { + self._selectionOverlayView.backgroundColor = UIColor.clear }, completion: nil) } } } } -public class WemoDeviceCellView: WemoCellView { - private var _ordinal: Int = 0 - private var _nameLabel: UILabel = UILabel() - private var _ordinalLabel: UILabel = UILabel() - private var _indicator: SwitchIndicatorView = SwitchIndicatorView() +open class WemoDeviceCellView: WemoCellView +{ + fileprivate var _ordinal: Int = 0 + fileprivate var _nameLabel: UILabel = UILabel() + fileprivate var _ordinalLabel: UILabel = UILabel() + fileprivate var _indicator: SwitchIndicatorView = SwitchIndicatorView() - static private var disabledAnnotationsColor = UIColor.darkGrayColor() - static private var enabledAnnotationsColor = UIColor.blackColor() + static fileprivate var disabledAnnotationsColor = UIColor.darkGray + static fileprivate var enabledAnnotationsColor = UIColor.black override init(frame: CGRect) { @@ -72,7 +73,7 @@ public class WemoDeviceCellView: WemoCellView { _nameLabel.numberOfLines = 3 _nameLabel.allowsDefaultTighteningForTruncation = true _nameLabel.adjustsFontSizeToFitWidth = true - _nameLabel.textColor = UIColor.whiteColor() + _nameLabel.textColor = UIColor.white self.contentView.addSubview(_nameLabel) _ordinalLabel.font = UIFont(name: "Orbitron-Medium", size: 21.0) @@ -91,7 +92,7 @@ public class WemoDeviceCellView: WemoCellView { // MARK: Overrides - override public func layoutSubviews() + override open func layoutSubviews() { super.layoutSubviews() @@ -128,7 +129,7 @@ public class WemoDeviceCellView: WemoCellView { { didSet { - _nameLabel.text = self.deviceName.uppercaseString + _nameLabel.text = self.deviceName.uppercased() self.setNeedsLayout() } } @@ -167,7 +168,8 @@ public class WemoDeviceCellView: WemoCellView { } } -public class WemoActionCellView: WemoCellView { +open class WemoActionCellView: WemoCellView +{ var textLabel: UILabel = UILabel() override init(frame: CGRect) @@ -175,8 +177,8 @@ public class WemoActionCellView: WemoCellView { super.init(frame: frame) self.textLabel.font = UIFont(name: "Orbitron-Medium", size: 21.0) - self.textLabel.textColor = UIColor.whiteColor() - self.textLabel.textAlignment = .Center + self.textLabel.textColor = UIColor.white + self.textLabel.textAlignment = .center self.addSubview(self.textLabel) } @@ -185,7 +187,7 @@ public class WemoActionCellView: WemoCellView { fatalError("unsupported") } - override public func layoutSubviews() + override open func layoutSubviews() { super.layoutSubviews() self.textLabel.frame = self.bounds @@ -196,9 +198,9 @@ public class WemoActionCellView: WemoCellView { didSet { if (enabled) { - self.textLabel.textColor = UIColor.whiteColor() + self.textLabel.textColor = UIColor.white } else { - self.textLabel.textColor = UIColor.darkGrayColor() + self.textLabel.textColor = UIColor.darkGray } } } diff --git a/XIONControlPanel/Views/XIONLogoView.swift b/XIONControlPanel/Views/XIONLogoView.swift index 6f9d108..e8c675d 100644 --- a/XIONControlPanel/Views/XIONLogoView.swift +++ b/XIONControlPanel/Views/XIONLogoView.swift @@ -10,24 +10,24 @@ import UIKit class XIONLogoView: UIView { - private var _xionLogoImageView: UIImageView = UIImageView() - private var _logoInnerRingImageView: UIImageView = UIImageView() - private var _logoOuterRingImageView: UIImageView = UIImageView() + fileprivate var _xionLogoImageView: UIImageView = UIImageView() + fileprivate var _logoInnerRingImageView: UIImageView = UIImageView() + fileprivate var _logoOuterRingImageView: UIImageView = UIImageView() override init(frame: CGRect) { super.init(frame: frame) - self.backgroundColor = UIColor.blackColor() + self.backgroundColor = UIColor.black _xionLogoImageView.image = UIImage(named: "XIONLogoWithRing") - _xionLogoImageView.contentMode = .ScaleAspectFit + _xionLogoImageView.contentMode = .scaleAspectFit _logoInnerRingImageView.image = UIImage(named: "XIONLogoInnerRing") - _logoInnerRingImageView.contentMode = .ScaleAspectFit + _logoInnerRingImageView.contentMode = .scaleAspectFit _logoOuterRingImageView.image = UIImage(named: "XIONLogoOuterRing") - _logoOuterRingImageView.contentMode = .ScaleAspectFit + _logoOuterRingImageView.contentMode = .scaleAspectFit self.addSubview(_logoOuterRingImageView) self.addSubview(_logoInnerRingImageView) @@ -55,7 +55,7 @@ class XIONLogoView: UIView { self.stopAnimating() - let duration: NSTimeInterval = 20.0 + let duration: TimeInterval = 20.0 let clockwiseAnim = CABasicAnimation(keyPath: "transform.rotation") clockwiseAnim.fromValue = 0.0 @@ -69,8 +69,8 @@ class XIONLogoView: UIView counterClockwiseAnim.duration = duration counterClockwiseAnim.repeatCount = Float.infinity - _logoInnerRingImageView.layer.addAnimation(clockwiseAnim, forKey: "LogoClockwiseAnimation") - _logoOuterRingImageView.layer.addAnimation(counterClockwiseAnim, forKey: "LogoCounterclockwiseAnimation") + _logoInnerRingImageView.layer.add(clockwiseAnim, forKey: "LogoClockwiseAnimation") + _logoOuterRingImageView.layer.add(counterClockwiseAnim, forKey: "LogoCounterclockwiseAnimation") } func stopAnimating() From d295b80eaba0efb4463af6df6e6829d314babbb7 Mon Sep 17 00:00:00 2001 From: Charles Magahern Date: Mon, 4 Sep 2017 18:31:34 -0700 Subject: [PATCH 2/2] Last remaining fixes for swift 3 --- XIONControlPanel.xcodeproj/project.pbxproj | 4 +++- .../Controllers/VisualizationViewController.swift | 2 +- XIONControlPanel/Controllers/WemoServer.swift | 6 +++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/XIONControlPanel.xcodeproj/project.pbxproj b/XIONControlPanel.xcodeproj/project.pbxproj index f5e5097..1488682 100644 --- a/XIONControlPanel.xcodeproj/project.pbxproj +++ b/XIONControlPanel.xcodeproj/project.pbxproj @@ -247,7 +247,7 @@ TargetAttributes = { 0C3CAEA31C3350C800B856AD = { CreatedOnToolsVersion = 7.2; - DevelopmentTeam = 64S2YWUDC5; + DevelopmentTeam = FZ6BMA5HA9; LastSwiftMigration = 0810; }; }; @@ -421,6 +421,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEVELOPMENT_TEAM = FZ6BMA5HA9; INFOPLIST_FILE = "$(SRCROOT)/XIONControlPanel/SupportingFiles/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( @@ -443,6 +444,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEVELOPMENT_TEAM = FZ6BMA5HA9; INFOPLIST_FILE = "$(SRCROOT)/XIONControlPanel/SupportingFiles/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( diff --git a/XIONControlPanel/Controllers/VisualizationViewController.swift b/XIONControlPanel/Controllers/VisualizationViewController.swift index b94a489..457595f 100644 --- a/XIONControlPanel/Controllers/VisualizationViewController.swift +++ b/XIONControlPanel/Controllers/VisualizationViewController.swift @@ -34,7 +34,7 @@ class VisualizationViewController: UIViewController override func loadView() { - let opts = [SCNView.Option.preferredRenderingAPI.rawValue : SCNRenderingAPI.openGLES2] + let opts = [SCNView.Option.preferredRenderingAPI.rawValue : SCNRenderingAPI.openGLES2.rawValue] let view = SCNView(frame: UIScreen.main.bounds, options: opts) view.backgroundColor = UIColor.black view.scene = _scene diff --git a/XIONControlPanel/Controllers/WemoServer.swift b/XIONControlPanel/Controllers/WemoServer.swift index 1d3b319..9c74fb6 100644 --- a/XIONControlPanel/Controllers/WemoServer.swift +++ b/XIONControlPanel/Controllers/WemoServer.swift @@ -156,14 +156,14 @@ internal class FetchDevicesOperation : WemoOperation { let semaphore = Semaphore(value: 0) let url = self.baseURL.appendingPathComponent("api/environment") - let task = self.session.dataTask(with: url, completionHandler: { (data: Data?, response: URLResponse?, error: NSError?) -> Void in + let task = self.session.dataTask(with: url, completionHandler: { (data: Data?, response: URLResponse?, error: Error?) -> Void in if (data != nil) { self.devices = self._parseDevices(data!) } else { - self.error = NSError.xionError(.connectionError, underlying: error) + self.error = error } semaphore.signal() - } as! (Data?, URLResponse?, Error?) -> Void) + }) task.resume() semaphore.wait() }