iPhone Support

This commit is contained in:
Charles Magahern
2016-07-24 00:14:04 -07:00
parent 2f5c807dc6
commit 56de300889
17 changed files with 143 additions and 59 deletions

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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 {

View File

@@ -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()

View File

@@ -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

View File

@@ -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
}

View File

@@ -45,6 +45,8 @@
<array>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>

View File

@@ -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

View File

@@ -7,8 +7,10 @@
import Foundation
extension NSURL {
var requestParameters: [String : String]? {
extension NSURL
{
var requestParameters: [String : String]?
{
get
{
let urlComponents = self.absoluteString.componentsSeparatedByString("/")

View File

@@ -8,7 +8,8 @@
import Foundation
class Semaphore {
class Semaphore
{
private var _semaphore: dispatch_semaphore_t
init(value: Int)

View File

@@ -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)!)
}

View File

@@ -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()

View File

@@ -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
)

View File

@@ -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()

View File

@@ -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)

View File

@@ -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()