From 697a7e1de9439fc496617be34a364b1548f42a24 Mon Sep 17 00:00:00 2001 From: Charles Magahern Date: Thu, 31 Dec 2015 23:29:48 -0800 Subject: [PATCH] Automatically update devices on an interval --- .../Controllers/MainViewController.swift | 21 ++++++ .../Controllers/SwitchesViewController.swift | 66 ++++++++++++++++++- XIONControlPanel/Models/WemoDevice.swift | 20 +++++- XIONControlPanel/Views/WemoCellView.swift | 2 + 4 files changed, 107 insertions(+), 2 deletions(-) diff --git a/XIONControlPanel/Controllers/MainViewController.swift b/XIONControlPanel/Controllers/MainViewController.swift index 5f0468b..480140e 100644 --- a/XIONControlPanel/Controllers/MainViewController.swift +++ b/XIONControlPanel/Controllers/MainViewController.swift @@ -13,6 +13,7 @@ class MainViewController: UIViewController, SwitchesViewControllerDelegate { private var _visualizationController: VisualizationViewController = VisualizationViewController() private var _switchesController: SwitchesViewController = SwitchesViewController() private var _headerView: HeaderView = HeaderView() + private var _updateDevices: Bool = false override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { @@ -92,6 +93,7 @@ class MainViewController: UIViewController, SwitchesViewControllerDelegate { _server.connect { (error: NSError?) -> Void in if (error == nil) { self._reloadDevices() + self._startUpdatingDevices() } else { self._updateConnectivityStatus(.Error) } @@ -164,8 +166,27 @@ class MainViewController: UIViewController, SwitchesViewControllerDelegate { } else { self.devices = [] self._updateConnectivityStatus(.Error) + self._stopUpdatingDevices() } } }) } + + internal func _startUpdatingDevices() + { + _updateDevices = true + + let interval = dispatch_time(DISPATCH_TIME_NOW, Int64(10 * Double(NSEC_PER_SEC))) + dispatch_after(interval, dispatch_get_main_queue()) { () -> Void in + if (self._updateDevices) { + self._reloadDevices() + self._startUpdatingDevices() + } + } + } + + internal func _stopUpdatingDevices() + { + _updateDevices = false + } } diff --git a/XIONControlPanel/Controllers/SwitchesViewController.swift b/XIONControlPanel/Controllers/SwitchesViewController.swift index 5a3cbd9..30c2f3d 100644 --- a/XIONControlPanel/Controllers/SwitchesViewController.swift +++ b/XIONControlPanel/Controllers/SwitchesViewController.swift @@ -25,6 +25,7 @@ class SwitchesViewController: UIViewController, weak var delegate: SwitchesViewControllerDelegate? private var _collectionView: UICollectionView = UICollectionView(frame: CGRectZero, collectionViewLayout: UICollectionViewFlowLayout()) + private var _currentDevicesHash: Int = 0 static private let collectionViewDeviceSwitchCellReuseIdentifier = "DeviceSwitchReuseID" static private let collectionViewActionCellReuseIdentifier = "ActionCellReuseID" @@ -87,7 +88,69 @@ class SwitchesViewController: UIViewController, { didSet { - _collectionView.reloadData() + let hash = self.devices.reduce(0, combine: {$0 ^ $1.hashValue}) + if (hash != _currentDevicesHash) { + // sort by name + self.devices.sortInPlace({ (d1: WemoDevice, d2: WemoDevice) -> Bool in + return (d1.name.compare(d2.name) == .OrderedAscending) + }) + + // replace "Dance Dance Revolution" names with "DDR" to save space + for device in self.devices { + if let range = device.name.rangeOfString("Dance Dance Revolution") { + device.name.replaceRange(range, with: "DDR") + } + } + + let previousSet = NSOrderedSet(array: oldValue) + let newSet = NSOrderedSet(array: self.devices) + var insertedIndexPaths: [NSIndexPath] = [] + var updatedIndexPaths: [NSIndexPath] = [] + var deletedIndexPaths: [NSIndexPath] = [] + + // if we have devices now and we didn't before, or vice versa, + // we need to update the action cells + if ((oldValue.count == 0 && self.devices.count != 0) || (self.devices.count == 0 && oldValue.count != 0)) { + for var actionCellIdx = 0; actionCellIdx < ActionCell.count; ++actionCellIdx { + let actionCellIndexPath = NSIndexPath(forItem: actionCellIdx, inSection: 0) + updatedIndexPaths.append(actionCellIndexPath) + } + } + + // find deletes and updates + for (idx, device) in previousSet.enumerate() { + let itemIndex = idx + ActionCell.count + let curIndexPath = NSIndexPath(forItem: itemIndex, inSection: 0) + + if (!newSet.containsObject(device)) { + deletedIndexPaths.append(curIndexPath) + } else if (idx < newSet.count) { + let deviceInNewSet = newSet.objectAtIndex(idx) as! WemoDevice + if (deviceInNewSet != (device as! WemoDevice)) { + updatedIndexPaths.append(curIndexPath) + } + } + } + + // find insertions + for (idx, device) in newSet.enumerate() { + if (!previousSet.containsObject(device)) { + let itemIndex = idx + ActionCell.count + let insertedIndexPath = NSIndexPath(forItem: itemIndex, inSection: 0) + insertedIndexPaths.append(insertedIndexPath) + } + } + + UIView.performWithoutAnimation { () -> Void in + self._collectionView.performBatchUpdates({ () -> Void in + self._collectionView.deleteItemsAtIndexPaths(deletedIndexPaths) + self._collectionView.reloadItemsAtIndexPaths(updatedIndexPaths) + self._collectionView.insertItemsAtIndexPaths(insertedIndexPaths) + }, completion: nil) + } + + _currentDevicesHash = hash + } } } @@ -114,6 +177,7 @@ class SwitchesViewController: UIViewController, let deviceIdx = indexPath.item - ActionCell.count let device = self.devices[deviceIdx] cell.device = device + cell.toggled = (device.state == .On) cell.ordinal = deviceIdx + 1 return cell diff --git a/XIONControlPanel/Models/WemoDevice.swift b/XIONControlPanel/Models/WemoDevice.swift index 9912e3e..5eed0b4 100644 --- a/XIONControlPanel/Models/WemoDevice.swift +++ b/XIONControlPanel/Models/WemoDevice.swift @@ -8,7 +8,7 @@ import Foundation -class WemoDevice { +class WemoDevice: Hashable { enum State { case Off case On @@ -57,4 +57,22 @@ class WemoDevice { self.serial = String(serial) } } + + var hashValue: Int + { + var hash: Int = 0x0 + hash ^= self.name.hash + hash ^= self.host.hash + hash ^= self.model.hash + hash ^= self.state.hashValue + hash ^= self.type.hashValue + hash ^= self.serial.hashValue + + return hash + } +} + +func ==(lhs: WemoDevice, rhs: WemoDevice) -> Bool +{ + return (lhs.serial == rhs.serial) } diff --git a/XIONControlPanel/Views/WemoCellView.swift b/XIONControlPanel/Views/WemoCellView.swift index 44005b8..9ad6379 100644 --- a/XIONControlPanel/Views/WemoCellView.swift +++ b/XIONControlPanel/Views/WemoCellView.swift @@ -132,6 +132,7 @@ public class WemoDeviceCellView: WemoCellView { { _device = device _nameLabel.text = _device?.name.uppercaseString + self.setNeedsLayout() } } @@ -146,6 +147,7 @@ public class WemoDeviceCellView: WemoCellView { { _ordinal = ordinal _ordinalLabel.text = String(format: "%.2d", _ordinal) + self.setNeedsLayout() } }