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