iPhone Support
This commit is contained in:
@@ -109,8 +109,8 @@
|
||||
0C20E2B61C33514100BA789B /* Controllers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0C41EF491C34B51500AF847F /* SwitchesViewController.swift */,
|
||||
0C20E2BA1C33529700BA789B /* MainViewController.swift */,
|
||||
0C41EF491C34B51500AF847F /* SwitchesViewController.swift */,
|
||||
0C20E2BC1C33534F00BA789B /* VisualizationViewController.swift */,
|
||||
0CAA32781C361A2400B353CF /* WemoServer.swift */,
|
||||
);
|
||||
@@ -427,7 +427,7 @@
|
||||
PROVISIONING_PROFILE = "";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "XIONControlPanel/SupportingFiles/XIONControlPanel-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
TARGETED_DEVICE_FAMILY = 2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -444,7 +444,7 @@
|
||||
PRODUCT_NAME = XION;
|
||||
PROVISIONING_PROFILE = "";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "XIONControlPanel/SupportingFiles/XIONControlPanel-Bridging-Header.h";
|
||||
TARGETED_DEVICE_FAMILY = 2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
import UIKit
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate
|
||||
{
|
||||
var window: UIWindow?
|
||||
var mainViewController: MainViewController = MainViewController()
|
||||
|
||||
@@ -36,6 +37,14 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask
|
||||
{
|
||||
return UIInterfaceOrientationMask.Landscape
|
||||
var mask: UIInterfaceOrientationMask = .Portrait
|
||||
|
||||
if (UIDevice.currentDevice().userInterfaceIdiom == .Phone) {
|
||||
mask = UIInterfaceOrientationMask.Portrait
|
||||
} else {
|
||||
mask = UIInterfaceOrientationMask.All
|
||||
}
|
||||
|
||||
return mask
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
class MainViewController: UIViewController, SwitchesViewControllerDelegate {
|
||||
class MainViewController: UIViewController, SwitchesViewControllerDelegate
|
||||
{
|
||||
private var _server: WemoServer
|
||||
private var _visualizationController: VisualizationViewController = VisualizationViewController()
|
||||
private var _switchesController: SwitchesViewController = SwitchesViewController()
|
||||
@@ -53,11 +54,13 @@ class MainViewController: UIViewController, SwitchesViewControllerDelegate {
|
||||
super.viewDidLayoutSubviews()
|
||||
|
||||
let bounds = self.view.bounds
|
||||
let horizontalSizeClass = self.traitCollection.horizontalSizeClass
|
||||
|
||||
let headerBounds = CGRect(
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
width: bounds.size.width,
|
||||
height: rint(bounds.size.height / 10.0)
|
||||
height: rint(bounds.size.height / 8.0)
|
||||
)
|
||||
let bodyBounds = CGRect(
|
||||
x: 0.0,
|
||||
@@ -76,10 +79,20 @@ class MainViewController: UIViewController, SwitchesViewControllerDelegate {
|
||||
)
|
||||
_visualizationController.view.frame = visualizationFrame
|
||||
|
||||
var switchesOriginX: CGFloat = 0.0
|
||||
var switchesWidth: CGFloat = 0.0
|
||||
if (horizontalSizeClass == .Regular) {
|
||||
switchesOriginX = CGRectGetMaxX(visualizationFrame)
|
||||
switchesWidth = bodyBounds.size.width - visualizationFrame.size.width
|
||||
} else {
|
||||
switchesOriginX = 0.0
|
||||
switchesWidth = bodyBounds.size.width
|
||||
}
|
||||
|
||||
let switchesControllerFrame = CGRect(
|
||||
x: CGRectGetMaxX(visualizationFrame),
|
||||
x: switchesOriginX,
|
||||
y: bodyBounds.origin.y,
|
||||
width: bodyBounds.size.width - visualizationFrame.size.width,
|
||||
width: switchesWidth,
|
||||
height: bodyBounds.size.height
|
||||
)
|
||||
_switchesController.view.frame = switchesControllerFrame
|
||||
@@ -104,6 +117,12 @@ class MainViewController: UIViewController, SwitchesViewControllerDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
|
||||
{
|
||||
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
|
||||
_updateSizeClassPresentation()
|
||||
}
|
||||
|
||||
override func prefersStatusBarHidden() -> Bool
|
||||
{
|
||||
return true
|
||||
@@ -133,6 +152,16 @@ class MainViewController: UIViewController, SwitchesViewControllerDelegate {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal func _updateSizeClassPresentation()
|
||||
{
|
||||
let horizontalSizeClass = self.traitCollection.horizontalSizeClass
|
||||
if (horizontalSizeClass == .Regular) {
|
||||
_visualizationController.view.hidden = false
|
||||
} else {
|
||||
_visualizationController.view.hidden = true
|
||||
}
|
||||
}
|
||||
|
||||
internal func _updateVisualization(animated: Bool)
|
||||
{
|
||||
var activatedDevicesCount = 0
|
||||
@@ -152,6 +181,7 @@ class MainViewController: UIViewController, SwitchesViewControllerDelegate {
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue()) { () -> Void in
|
||||
self._headerView.connectionStatusView.connectivityStatus = status
|
||||
self._headerView.setNeedsLayout()
|
||||
self._visualizationController.connectionStatus = status
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,13 @@ import Darwin
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
protocol SwitchesViewControllerDelegate: class {
|
||||
protocol SwitchesViewControllerDelegate: class
|
||||
{
|
||||
func switchesViewControllerDidToggleDevices(controller: SwitchesViewController, devices: [WemoDevice])
|
||||
}
|
||||
|
||||
extension SwitchesViewControllerDelegate {
|
||||
extension SwitchesViewControllerDelegate
|
||||
{
|
||||
func switchesViewControllerDidToggleDevices(controller: SwitchesViewController, devices: [WemoDevice]) {}
|
||||
}
|
||||
|
||||
@@ -30,9 +32,9 @@ class SwitchesViewController: UIViewController,
|
||||
static private let collectionViewDeviceSwitchCellReuseIdentifier = "DeviceSwitchReuseID"
|
||||
static private let collectionViewActionCellReuseIdentifier = "ActionCellReuseID"
|
||||
static private let collectionViewCellsSpacing: CGFloat = 5.0
|
||||
static private let collectionViewCellsPerRow = 3
|
||||
|
||||
private enum ActionCell: Int {
|
||||
private enum ActionCell: Int
|
||||
{
|
||||
case AllOn
|
||||
case AllOff
|
||||
|
||||
@@ -181,9 +183,20 @@ class SwitchesViewController: UIViewController,
|
||||
sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize
|
||||
{
|
||||
let spacing = SwitchesViewController.collectionViewCellsSpacing
|
||||
let cellsPerRow = CGFloat(SwitchesViewController.collectionViewCellsPerRow)
|
||||
let dimensions = floor((collectionView.bounds.size.width / cellsPerRow) - ((spacing * (cellsPerRow - 1.0)) / cellsPerRow))
|
||||
let bounds = collectionView.bounds
|
||||
var cellsPerRow: CGFloat = 0.0
|
||||
|
||||
switch (self.traitCollection.horizontalSizeClass) {
|
||||
case .Regular, .Compact where (bounds.size.width >= 400.0):
|
||||
cellsPerRow = 3.0
|
||||
break
|
||||
case .Compact:
|
||||
cellsPerRow = 2.0
|
||||
default:
|
||||
cellsPerRow = 2.0
|
||||
}
|
||||
|
||||
let dimensions = floor((collectionView.bounds.size.width / cellsPerRow) - ((spacing * (cellsPerRow - 1.0)) / cellsPerRow))
|
||||
if (indexPath.item < ActionCell.count) {
|
||||
return CGSize(width: collectionView.bounds.size.width, height: rint(dimensions / 2.0))
|
||||
} else {
|
||||
|
||||
@@ -14,7 +14,8 @@ import UIKit
|
||||
|
||||
let π = CGFloat(M_PI)
|
||||
|
||||
class VisualizationViewController: UIViewController {
|
||||
class VisualizationViewController: UIViewController
|
||||
{
|
||||
private var _scene: SCNScene = SCNScene()
|
||||
private var _sceneView: SCNView?
|
||||
private var _cameraNode: SCNNode = SCNNode()
|
||||
|
||||
@@ -8,14 +8,16 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
enum ConnectionStatus {
|
||||
enum ConnectionStatus
|
||||
{
|
||||
case Disconnected
|
||||
case Connecting
|
||||
case Connected
|
||||
case Error
|
||||
}
|
||||
|
||||
class WemoServer {
|
||||
class WemoServer
|
||||
{
|
||||
private(set) var baseURL: NSURL
|
||||
private(set) var connected: Bool = false
|
||||
|
||||
@@ -108,7 +110,8 @@ class WemoServer {
|
||||
}
|
||||
}
|
||||
|
||||
internal class WemoOperation : NSOperation {
|
||||
internal class WemoOperation : NSOperation
|
||||
{
|
||||
var baseURL: NSURL
|
||||
var session: NSURLSession
|
||||
|
||||
@@ -121,7 +124,8 @@ internal class WemoOperation : NSOperation {
|
||||
}
|
||||
}
|
||||
|
||||
internal class ConnectOperation : WemoOperation {
|
||||
internal class ConnectOperation : WemoOperation
|
||||
{
|
||||
override func main()
|
||||
{
|
||||
let semaphore = Semaphore(value: 0)
|
||||
@@ -140,7 +144,8 @@ internal class ConnectOperation : WemoOperation {
|
||||
}
|
||||
}
|
||||
|
||||
internal class FetchDevicesOperation : WemoOperation {
|
||||
internal class FetchDevicesOperation : WemoOperation
|
||||
{
|
||||
internal(set) var devices: [WemoDevice] = []
|
||||
|
||||
override func main()
|
||||
@@ -176,7 +181,8 @@ internal class FetchDevicesOperation : WemoOperation {
|
||||
}
|
||||
}
|
||||
|
||||
internal class ToggleDeviceOperation : WemoOperation {
|
||||
internal class ToggleDeviceOperation : WemoOperation
|
||||
{
|
||||
var device: WemoDevice
|
||||
var state: WemoDevice.State
|
||||
|
||||
|
||||
@@ -8,13 +8,16 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
class WemoDevice: Hashable {
|
||||
enum State {
|
||||
class WemoDevice: Hashable
|
||||
{
|
||||
enum State
|
||||
{
|
||||
case Off
|
||||
case On
|
||||
}
|
||||
|
||||
enum Type {
|
||||
enum Type
|
||||
{
|
||||
case Switch
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
<array>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
|
||||
@@ -8,12 +8,14 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
enum XIONErrorCode: Int {
|
||||
enum XIONErrorCode: Int
|
||||
{
|
||||
case Unknown
|
||||
case ConnectionError
|
||||
}
|
||||
|
||||
extension NSError {
|
||||
extension NSError
|
||||
{
|
||||
private static let XIONErrorDomain = "com.xionsf.controlpanel"
|
||||
|
||||
class func xionError(code: XIONErrorCode) -> NSError
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
extension NSURL {
|
||||
var requestParameters: [String : String]? {
|
||||
extension NSURL
|
||||
{
|
||||
var requestParameters: [String : String]?
|
||||
{
|
||||
get
|
||||
{
|
||||
let urlComponents = self.absoluteString.componentsSeparatedByString("/")
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
class Semaphore {
|
||||
class Semaphore
|
||||
{
|
||||
private var _semaphore: dispatch_semaphore_t
|
||||
|
||||
init(value: Int)
|
||||
|
||||
@@ -8,8 +8,10 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
class StandardErrorOutputStream: OutputStreamType {
|
||||
func write(string: String) {
|
||||
class StandardErrorOutputStream: OutputStreamType
|
||||
{
|
||||
func write(string: String)
|
||||
{
|
||||
let stderr = NSFileHandle.fileHandleWithStandardError()
|
||||
stderr.writeData(string.dataUsingEncoding(NSUTF8StringEncoding)!)
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
class ConnectionStatusView: UIView {
|
||||
class ConnectionStatusView: UIView
|
||||
{
|
||||
private var _connectivityStatus: ConnectionStatus = .Disconnected
|
||||
private var _japaneseLabel: UILabel = UILabel()
|
||||
private var _englishLabel: UILabel = UILabel()
|
||||
|
||||
@@ -10,7 +10,8 @@ import Darwin
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
class HeaderView: UIView {
|
||||
class HeaderView: UIView
|
||||
{
|
||||
var xionLogoView: XIONLogoView = XIONLogoView()
|
||||
var connectionStatusView: ConnectionStatusView = ConnectionStatusView()
|
||||
|
||||
@@ -58,31 +59,39 @@ class HeaderView: UIView {
|
||||
)
|
||||
self.xionLogoView.frame = logoFrame
|
||||
|
||||
let titleJPVerticalMargin: CGFloat = 5.0
|
||||
let titleLabelSize = _xionTitleLabel.sizeThatFits(bounds.size)
|
||||
let jpLabelSize = _xionJapaneseLabel.sizeThatFits(bounds.size)
|
||||
let totalLabelsHeight = titleLabelSize.height + titleJPVerticalMargin + jpLabelSize.height
|
||||
if (self.traitCollection.horizontalSizeClass == .Compact) {
|
||||
_xionTitleLabel.hidden = true
|
||||
_xionJapaneseLabel.hidden = true
|
||||
} else {
|
||||
_xionTitleLabel.hidden = false
|
||||
_xionJapaneseLabel.hidden = false
|
||||
|
||||
let titleFrame = CGRect(
|
||||
x: CGRectGetMaxX(logoFrame) + hpadding * 2.0,
|
||||
y: rint(bounds.size.height / 2.0 - totalLabelsHeight / 2.0),
|
||||
width: titleLabelSize.width,
|
||||
height: titleLabelSize.height
|
||||
)
|
||||
_xionTitleLabel.frame = titleFrame
|
||||
let titleJPVerticalMargin: CGFloat = 5.0
|
||||
let titleLabelSize = _xionTitleLabel.sizeThatFits(bounds.size)
|
||||
let jpLabelSize = _xionJapaneseLabel.sizeThatFits(bounds.size)
|
||||
let totalLabelsHeight = titleLabelSize.height + titleJPVerticalMargin + jpLabelSize.height
|
||||
|
||||
let titleFrame = CGRect(
|
||||
x: CGRectGetMaxX(logoFrame) + hpadding * 2.0,
|
||||
y: rint(bounds.size.height / 2.0 - totalLabelsHeight / 2.0),
|
||||
width: titleLabelSize.width,
|
||||
height: titleLabelSize.height
|
||||
)
|
||||
_xionTitleLabel.frame = titleFrame
|
||||
|
||||
let jpTitleFrame = CGRect(
|
||||
x: titleFrame.origin.x,
|
||||
y: CGRectGetMaxY(titleFrame) + titleJPVerticalMargin,
|
||||
width: jpLabelSize.width,
|
||||
height: jpLabelSize.height + 2.0
|
||||
)
|
||||
_xionJapaneseLabel.frame = jpTitleFrame
|
||||
}
|
||||
|
||||
let jpTitleFrame = CGRect(
|
||||
x: titleFrame.origin.x,
|
||||
y: CGRectGetMaxY(titleFrame) + titleJPVerticalMargin,
|
||||
width: jpLabelSize.width,
|
||||
height: jpLabelSize.height + 2.0
|
||||
)
|
||||
_xionJapaneseLabel.frame = jpTitleFrame
|
||||
|
||||
let connectionStatusDimensions = CGSize(width: rint((1.0 / 8.0) * bounds.size.width), height: bounds.size.height)
|
||||
let connectionStatusDimensions = self.connectionStatusView.sizeThatFits(bounds.size)
|
||||
let connectionStatusFrame = CGRect(
|
||||
x: bounds.size.width - connectionStatusDimensions.width,
|
||||
y: 0.0,
|
||||
x: bounds.size.width - connectionStatusDimensions.width - hpadding,
|
||||
y: rint(bounds.size.height / 2.0 - connectionStatusDimensions.height / 2.0),
|
||||
width: connectionStatusDimensions.width,
|
||||
height: connectionStatusDimensions.height
|
||||
)
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
class SwitchIndicatorView: UIView {
|
||||
class SwitchIndicatorView: UIView
|
||||
{
|
||||
private var _status: Bool = false
|
||||
private var _foregroundColor: UIColor = UIColor.whiteColor()
|
||||
private var _outerCircleLayer: CAShapeLayer = CAShapeLayer()
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
public class WemoCellView: UICollectionViewCell {
|
||||
public class WemoCellView: UICollectionViewCell
|
||||
{
|
||||
private var _selectionOverlayView: UIView = UIView()
|
||||
|
||||
static private var disabledBackgroundColor = UIColor(white: 0.2, alpha: 1.0)
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
class XIONLogoView: UIView {
|
||||
class XIONLogoView: UIView
|
||||
{
|
||||
private var _xionLogoImageView: UIImageView = UIImageView()
|
||||
private var _logoInnerRingImageView: UIImageView = UIImageView()
|
||||
private var _logoOuterRingImageView: UIImageView = UIImageView()
|
||||
|
||||
Reference in New Issue
Block a user