From 9bc995c8cbb80dab8b85277b45c62dcf2019ff12 Mon Sep 17 00:00:00 2001 From: Robbie Trencheny Date: Fri, 6 Jan 2017 22:00:37 -0800 Subject: [PATCH] Add SwiftLint and autocorrect --- .swiftlint.yml | 5 + .../NotificationService.swift | 44 +-- HomeAssistant.xcodeproj/project.pbxproj | 17 +- HomeAssistant/AppDelegate.swift | 52 ++-- .../Components/AutomationComponent.swift | 8 +- .../Components/BinarySensorComponent.swift | 12 +- .../Classes/Components/ClimateComponent.swift | 34 +-- .../Components/DeviceTrackerComponent.swift | 12 +- .../Classes/Components/FanComponent.swift | 17 +- .../Components/GarageDoorComponent.swift | 8 +- .../Classes/Components/GroupComponent.swift | 14 +- .../Components/InputBooleanComponent.swift | 2 +- .../Components/InputSelectComponent.swift | 8 +- .../Classes/Components/InputSlider.swift | 10 +- .../Classes/Components/LightComponent.swift | 15 +- .../Classes/Components/LockComponent.swift | 8 +- .../Components/MediaPlayerComponent.swift | 25 +- .../Classes/Components/SceneComponent.swift | 12 +- .../Classes/Components/ScriptComponent.swift | 8 +- .../Classes/Components/SensorComponent.swift | 8 +- .../Classes/Components/SunComponent.swift | 10 +- .../Classes/Components/SwitchComponent.swift | 8 +- .../Components/ThermostatComponent.swift | 8 +- .../Classes/Components/WeblinkComponent.swift | 8 +- .../Classes/Components/ZoneComponent.swift | 16 +- HomeAssistant/Classes/Entity.swift | 58 ++-- .../Classes/HA API Responses/Beacons.swift | 8 +- .../Classes/HA API Responses/Bootstrap.swift | 2 +- .../Classes/HA API Responses/Config.swift | 16 +- .../HA API Responses/DiscoveryInfo.swift | 8 +- .../Classes/HA API Responses/Events.swift | 8 +- .../Classes/HA API Responses/History.swift | 12 +- .../HA API Responses/PushConfiguration.swift | 26 +- .../HA API Responses/SSE/CallService.swift | 2 +- .../Classes/HA API Responses/SSE/Event.swift | 8 +- .../SSE/ServiceExecuted.swift | 2 +- .../HA API Responses/SSE/StateChanged.swift | 8 +- .../Classes/HA API Responses/Services.swift | 24 +- .../Classes/HA API Responses/Status.swift | 9 +- HomeAssistant/Classes/IdentifyRequest.swift | 10 +- .../Classes/PushRegistrationRequest.swift | 12 +- .../Classes/PushRegistrationResponse.swift | 10 +- HomeAssistant/Classes/SwitchableEntity.swift | 8 +- HomeAssistant/HAAPI.swift | 276 +++++++++--------- .../Utilities/NSURL+QueryDictionary.swift | 18 +- .../Utilities/OpenInChromeController.swift | 8 +- HomeAssistant/Utilities/Utils.swift | 62 ++-- HomeAssistant/Views/AboutViewController.swift | 59 ++-- .../Views/DevicesMapViewController.swift | 54 ++-- .../EntityAttributesViewController.swift | 46 ++- HomeAssistant/Views/EurekaLocationRow.swift | 36 +-- HomeAssistant/Views/GroupViewController.swift | 67 +++-- .../Views/RootTabBarViewController.swift | 70 ++--- .../Views/SettingsDetailViewController.swift | 20 +- .../Views/SettingsViewController.swift | 139 +++++---- .../MjpegStreamingController.swift | 54 ++-- .../NotificationViewController.swift | 42 +-- 57 files changed, 780 insertions(+), 771 deletions(-) create mode 100644 .swiftlint.yml diff --git a/.swiftlint.yml b/.swiftlint.yml new file mode 100644 index 000000000..e37dbd05b --- /dev/null +++ b/.swiftlint.yml @@ -0,0 +1,5 @@ +excluded: + - fastlane + - HomeAssistantTests + - HomeAssistantUITests + - Pods diff --git a/APNSAttachmentService/NotificationService.swift b/APNSAttachmentService/NotificationService.swift index 34d5edea1..d289457ba 100644 --- a/APNSAttachmentService/NotificationService.swift +++ b/APNSAttachmentService/NotificationService.swift @@ -10,19 +10,19 @@ import UserNotifications import MobileCoreServices final class NotificationService: UNNotificationServiceExtension { - + private var contentHandler: ((UNNotificationContent) -> Void)? private var bestAttemptContent: UNMutableNotificationContent? - + private var baseURL: String = "" private var apiPassword: String = "" - - override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void){ + + override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { print("APNSAttachmentService started!") print("Received userInfo", request.content.userInfo) self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) - + let prefs = UserDefaults(suiteName: "group.io.robbie.homeassistant")! if let url = prefs.string(forKey: "baseURL") { baseURL = url @@ -30,21 +30,21 @@ final class NotificationService: UNNotificationServiceExtension { if let pass = prefs.string(forKey: "apiPassword") { apiPassword = pass } - + func failEarly() { contentHandler(request.content) } - + guard let content = (request.content.mutableCopy() as? UNMutableNotificationContent) else { return failEarly() } - + var incomingAttachment: [String:Any] = [:] - + if let iAttachment = content.userInfo["attachment"] as? [String:Any] { incomingAttachment = iAttachment } - + if content.categoryIdentifier == "camera" && incomingAttachment["url"] == nil { guard let entityId = content.userInfo["entity_id"] as? String else { return failEarly() @@ -57,18 +57,18 @@ final class NotificationService: UNNotificationServiceExtension { return failEarly() } } - + guard let attachmentString = incomingAttachment["url"] as? String else { return failEarly() } - + guard let attachmentURL = URL(string: attachmentString) else { return failEarly() } - - var attachmentOptions:[String:Any] = [:] + + var attachmentOptions: [String:Any] = [:] if let attachmentContentType = incomingAttachment["content-type"] as? String { - var contentType:CFString = attachmentContentType as CFString + var contentType: CFString = attachmentContentType as CFString switch attachmentContentType.lowercased() { case "aiff": contentType = kUTTypeAudioInterchangeFileFormat @@ -102,12 +102,12 @@ final class NotificationService: UNNotificationServiceExtension { } guard let attachmentData = NSData(contentsOf:attachmentURL) else { return failEarly() } guard let attachment = UNNotificationAttachment.create(fileIdentifier: attachmentURL.lastPathComponent, data: attachmentData, options: attachmentOptions) else { return failEarly() } - + content.attachments.append(attachment) - + contentHandler(content.copy() as! UNNotificationContent) } - + override func serviceExtensionTimeWillExpire() { // Called just before the extension will be terminated by the system. // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used. @@ -115,17 +115,17 @@ final class NotificationService: UNNotificationServiceExtension { contentHandler(bestAttemptContent) } } - + } extension UNNotificationAttachment { - + /// Save the attachment URL to disk static func create(fileIdentifier: String, data: NSData, options: [AnyHashable : Any]?) -> UNNotificationAttachment? { let fileManager = FileManager.default let tmpSubFolderName = ProcessInfo.processInfo.globallyUniqueString let tmpSubFolderURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(tmpSubFolderName, isDirectory: true) - + do { try fileManager.createDirectory(at: tmpSubFolderURL!, withIntermediateDirectories: true, attributes: nil) let fileURL = tmpSubFolderURL?.appendingPathComponent(fileIdentifier) @@ -134,7 +134,7 @@ extension UNNotificationAttachment { } catch let error { print("Error when saving attachment: \(error)") } - + return nil } } diff --git a/HomeAssistant.xcodeproj/project.pbxproj b/HomeAssistant.xcodeproj/project.pbxproj index 396c72a48..7e065fa5c 100644 --- a/HomeAssistant.xcodeproj/project.pbxproj +++ b/HomeAssistant.xcodeproj/project.pbxproj @@ -935,14 +935,15 @@ buildConfigurationList = B657A9101CA646EB00121384 /* Build configuration list for PBXNativeTarget "HomeAssistant" */; buildPhases = ( EE918EC7744FD53B5836AC00 /* [CP] Check Pods Manifest.lock */, + B641BC261E20BAF3002CCBC1 /* Swiftlint */, B657A8E21CA646EB00121384 /* Sources */, B657A8E31CA646EB00121384 /* Frameworks */, B657A8E41CA646EB00121384 /* Resources */, - B6E8579C1CB1167200F96925 /* ShellScript */, B6E47E861CB9FD350027F6CA /* ShellScript */, D458061599D246B74530F402 /* [CP] Embed Pods Frameworks */, EB3BEB157867EEEFE3AFD2F3 /* [CP] Copy Pods Resources */, B6AAD7AC1D827DD40090B220 /* Embed App Extensions */, + B6E8579C1CB1167200F96925 /* ShellScript */, ); buildRules = ( ); @@ -1336,6 +1337,20 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-HomeAssistantTests/Pods-HomeAssistantTests-resources.sh\"\n"; showEnvVarsInLog = 0; }; + B641BC261E20BAF3002CCBC1 /* Swiftlint */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = Swiftlint; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi"; + }; B6E47E861CB9FD350027F6CA /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/HomeAssistant/AppDelegate.swift b/HomeAssistant/AppDelegate.swift index b05a17a5c..84fce8a28 100644 --- a/HomeAssistant/AppDelegate.swift +++ b/HomeAssistant/AppDelegate.swift @@ -16,8 +16,8 @@ import AlamofireNetworkActivityIndicator let realmConfig = Realm.Configuration( schemaVersion: 2, - - migrationBlock: { migration, oldSchemaVersion in + + migrationBlock: { _, oldSchemaVersion in if (oldSchemaVersion < 1) { } }) @@ -28,30 +28,30 @@ let realm = try! Realm(configuration: realmConfig) class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - + let prefs = UserDefaults(suiteName: "group.io.robbie.homeassistant")! - + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool { migrateUserDefaultsToAppGroups() Realm.Configuration.defaultConfiguration = realmConfig print("Realm file path", Realm.Configuration.defaultConfiguration.fileURL!.path) Fabric.with([Crashlytics.self]) - + NetworkActivityIndicatorManager.shared.isEnabled = true - + if #available(iOS 10, *) { UNUserNotificationCenter.current().delegate = self } - + Crashlytics.sharedInstance().setObjectValue(prefs.integer(forKey: "lastInstalledVersion"), forKey: "lastInstalledVersion") let buildNumber = Int(string: Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion")! as! String) prefs.set(buildNumber, forKey: "lastInstalledVersion") - + initAPI() - + return true } - + func initAPI() { if let baseURL = prefs.string(forKey: "baseURL") { print("Base URL is", baseURL) @@ -61,7 +61,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } firstly { HomeAssistantAPI.sharedInstance.Setup(baseAPIUrl: baseURL, APIPassword: apiPass) - }.then {_ in + }.then {_ in HomeAssistantAPI.sharedInstance.Connect() }.then { _ -> Void in if HomeAssistantAPI.sharedInstance.notificationsEnabled { @@ -80,7 +80,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } } } - + func applicationWillResignActive(_ application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. @@ -106,30 +106,30 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)}) - + self.prefs.setValue(deviceTokenString, forKey: "deviceToken") - + print("Registering push with deviceTokenString: \(deviceTokenString)") - + _ = HomeAssistantAPI.sharedInstance.registerDeviceForPush(deviceToken: deviceTokenString).then { pushId -> Void in print("Registered for push. PushID:", pushId) CLSLogv("Registered for push:", getVaList([pushId])) Crashlytics.sharedInstance().setUserIdentifier(pushId) self.prefs.setValue(pushId, forKey: "pushID") } - + } - + func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Swift.Error) { print("Error when trying to register for push", error) Crashlytics.sharedInstance().recordError(error) } - + func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { print("Received remote notification in completion handler!") - + let userInfoDict = userInfo as! [String:Any] - + if let hadict = userInfoDict["homeassistant"] as? [String:String] { if let command = hadict["command"] { switch command { @@ -150,17 +150,17 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } } } - + func application(_ application: UIApplication, handleActionWithIdentifier identifier: String?, forRemoteNotification userInfo: [AnyHashable : Any], withResponseInfo responseInfo: [AnyHashable : Any], completionHandler: @escaping () -> Void) { - var userInput:String? = nil + var userInput: String? = nil if let userText = responseInfo[UIUserNotificationActionResponseTypedTextKey] as? String { userInput = userText } let _ = HomeAssistantAPI.sharedInstance.handlePushAction(identifier: identifier!, userInfo: userInfo, userInput: userInput) } - + func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool { - var serviceData : [String:String] = url.queryItems! + var serviceData: [String:String] = url.queryItems! serviceData["sourceApplication"] = options[UIApplicationOpenURLOptionsKey.sourceApplication] as? String switch url.host! { case "call_service": // homeassistant://call_service/device_tracker.see?entity_id=device_tracker.entity @@ -182,7 +182,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { @available(iOS 10, *) extension AppDelegate: UNUserNotificationCenterDelegate { public func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { - var userText : String? = nil + var userText: String? = nil if let textInput = response as? UNTextInputNotificationResponse { userText = textInput.userText } @@ -194,7 +194,7 @@ extension AppDelegate: UNUserNotificationCenterDelegate { completionHandler() } } - + public func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { completionHandler([.alert, .badge, .sound]) } diff --git a/HomeAssistant/Classes/Components/AutomationComponent.swift b/HomeAssistant/Classes/Components/AutomationComponent.swift index c3a3ef330..9984beba5 100644 --- a/HomeAssistant/Classes/Components/AutomationComponent.swift +++ b/HomeAssistant/Classes/Components/AutomationComponent.swift @@ -10,15 +10,15 @@ import Foundation import ObjectMapper class Automation: Entity { - + dynamic var LastTriggered: Date? = nil - + override func mapping(map: Map) { super.mapping(map: map) - + LastTriggered <- (map["attributes.last_triggered"], HomeAssistantTimestampTransform()) } - + override var ComponentIcon: String { return "mdi:playlist-play" } diff --git a/HomeAssistant/Classes/Components/BinarySensorComponent.swift b/HomeAssistant/Classes/Components/BinarySensorComponent.swift index 64b4fbef7..8b0c160a6 100644 --- a/HomeAssistant/Classes/Components/BinarySensorComponent.swift +++ b/HomeAssistant/Classes/Components/BinarySensorComponent.swift @@ -10,23 +10,23 @@ import Foundation import ObjectMapper class BinarySensor: SwitchableEntity { - + dynamic var SensorClass: String? = nil - + override func mapping(map: Map) { super.mapping(map: map) - + SensorClass <- map["attributes.sensor_class"] } - + override var ComponentIcon: String { return "mdi:radiobox-blank" } - + override func StateIcon() -> String { if self.MobileIcon != nil { return self.MobileIcon! } if self.Icon != nil { return self.Icon! } - + let activated = (self.IsOn == false) if let sensorClass = self.SensorClass { switch (sensorClass) { diff --git a/HomeAssistant/Classes/Components/ClimateComponent.swift b/HomeAssistant/Classes/Components/ClimateComponent.swift index 4364205d7..899d9f0cc 100644 --- a/HomeAssistant/Classes/Components/ClimateComponent.swift +++ b/HomeAssistant/Classes/Components/ClimateComponent.swift @@ -12,7 +12,7 @@ import RealmSwift import Realm class Climate: Entity { - + dynamic var AuxHeat = false dynamic var AwayMode = false var CurrentHumidity = RealmOptional() @@ -29,10 +29,10 @@ class Climate: Entity { let SwingList = List() dynamic var SwingMode = false var Temperature = RealmOptional() - + override func mapping(map: Map) { super.mapping(map: map) - + AuxHeat <- (map["attributes.aux_heat"], ComponentBoolTransform(trueValue: "on", falseValue: "off")) AwayMode <- (map["attributes.away_mode"], ComponentBoolTransform(trueValue: "on", falseValue: "off")) CurrentHumidity.value <- map["attributes.current_humidity"] @@ -46,7 +46,7 @@ class Climate: Entity { OperationMode <- map["attributes.operation_mode"] SwingMode <- (map["attributes.swing_mode"], ComponentBoolTransform(trueValue: "on", falseValue: "off")) Temperature.value <- map["attributes.temperature"] - + var FanList: [String]? = nil FanList <- map["attributes.fan_list"] FanList?.forEach { option in @@ -54,7 +54,7 @@ class Climate: Entity { value.value = option self.FanList.append(value) } - + var OperationList: [String]? = nil OperationList <- map["attributes.operation_list"] OperationList?.forEach { option in @@ -62,7 +62,7 @@ class Climate: Entity { value.value = option self.OperationList.append(value) } - + var SwingList: [String]? = nil SwingList <- map["attributes.swing_list"] SwingList?.forEach { option in @@ -71,47 +71,47 @@ class Climate: Entity { self.SwingList.append(value) } } - + func TurnFanOn() { let _ = HomeAssistantAPI.sharedInstance.CallService(domain: "climate", service: "set_fan_mode", serviceData: ["entity_id": self.ID as AnyObject, "fan": "on" as AnyObject]) } - + func TurnFanOff() { let _ = HomeAssistantAPI.sharedInstance.CallService(domain: "climate", service: "set_fan_mode", serviceData: ["entity_id": self.ID as AnyObject, "fan": "off" as AnyObject]) } - + func SetAwayModeOn() { let _ = HomeAssistantAPI.sharedInstance.CallService(domain: "climate", service: "set_away_mode", serviceData: ["entity_id": self.ID as AnyObject, "away_mode": "on" as AnyObject]) } - + func SetAwayModeOff() { let _ = HomeAssistantAPI.sharedInstance.CallService(domain: "climate", service: "set_away_mode", serviceData: ["entity_id": self.ID as AnyObject, "away_mode": "off" as AnyObject]) } - + func SetTemperature(_ newTemp: Float) { let _ = HomeAssistantAPI.sharedInstance.CallService(domain: "climate", service: "set_temperature", serviceData: ["entity_id": self.ID as AnyObject, "temperature": newTemp as AnyObject]) } - + func SetHumidity(_ newHumidity: Int) { let _ = HomeAssistantAPI.sharedInstance.CallService(domain: "climate", service: "set_humidity", serviceData: ["entity_id": self.ID as AnyObject, "humidity": newHumidity as AnyObject]) } - + func SetSwingMode(_ newSwingMode: String) { let _ = HomeAssistantAPI.sharedInstance.CallService(domain: "climate", service: "set_swing_mode", serviceData: ["entity_id": self.ID as AnyObject, "swing_mode": newSwingMode as AnyObject]) } - + func SetOperationMode(_ newOperationMode: String) { let _ = HomeAssistantAPI.sharedInstance.CallService(domain: "climate", service: "set_operation_mode", serviceData: ["entity_id": self.ID as AnyObject, "operation_mode": newOperationMode as AnyObject]) } - + func TurnAuxHeatOn() { let _ = HomeAssistantAPI.sharedInstance.CallService(domain: "climate", service: "set_aux_heat", serviceData: ["entity_id": self.ID as AnyObject, "aux_heat": "on" as AnyObject]) } - + func TurnAuxHeatOff() { let _ = HomeAssistantAPI.sharedInstance.CallService(domain: "climate", service: "set_aux_heat", serviceData: ["entity_id": self.ID as AnyObject, "aux_heat": "off" as AnyObject]) } - + override var ComponentIcon: String { return "mdi:nest-thermostat" } diff --git a/HomeAssistant/Classes/Components/DeviceTrackerComponent.swift b/HomeAssistant/Classes/Components/DeviceTrackerComponent.swift index 65a60f4bb..8d37d86bc 100644 --- a/HomeAssistant/Classes/Components/DeviceTrackerComponent.swift +++ b/HomeAssistant/Classes/Components/DeviceTrackerComponent.swift @@ -12,23 +12,23 @@ import RealmSwift import CoreLocation class DeviceTracker: Entity { - + var Latitude = RealmOptional() var Longitude = RealmOptional() var Battery = RealmOptional() var GPSAccuracy = RealmOptional() // It's a double for direct use in CLLocationDistance dynamic var IsHome: Bool = false - + override func mapping(map: Map) { super.mapping(map: map) - + Latitude.value <- map["attributes.latitude"] Longitude.value <- map["attributes.longitude"] Battery.value <- map["attributes.battery"] GPSAccuracy.value <- map["attributes.gps_accuracy"] IsHome <- (map["state"], ComponentBoolTransform(trueValue: "home", falseValue: "not_home")) } - + func locationCoordinates() -> CLLocationCoordinate2D { if self.Latitude.value != nil && self.Longitude.value != nil { return CLLocationCoordinate2D(latitude: self.Latitude.value!, longitude: self.Longitude.value!) @@ -36,7 +36,7 @@ class DeviceTracker: Entity { return CLLocationCoordinate2D() } } - + func location() -> CLLocation { if let accr = self.GPSAccuracy.value { return CLLocation(coordinate: self.locationCoordinates(), altitude: 0, horizontalAccuracy: accr, verticalAccuracy: -1, timestamp: Date()) @@ -48,7 +48,7 @@ class DeviceTracker: Entity { } } } - + override var ComponentIcon: String { return "mdi:account" } diff --git a/HomeAssistant/Classes/Components/FanComponent.swift b/HomeAssistant/Classes/Components/FanComponent.swift index 61dfe2cc5..4ead06c62 100644 --- a/HomeAssistant/Classes/Components/FanComponent.swift +++ b/HomeAssistant/Classes/Components/FanComponent.swift @@ -10,33 +10,32 @@ import Foundation import ObjectMapper class Fan: Entity { - + dynamic var Oscillating = false dynamic var Speed: String? = nil dynamic var SupportsSetSpeed: Bool = false dynamic var SupportsOscillate: Bool = false var SupportedFeatures: Int? - + override func mapping(map: Map) { super.mapping(map: map) - + Oscillating <- map["attributes.oscillating"] Speed <- map["attributes.speed"] - + SupportedFeatures <- map["attributes.supported_features"] - - + if let supported = self.SupportedFeatures { let features = FanSupportedFeatures(rawValue: supported) self.SupportsSetSpeed = features.contains(.SetSpeed) self.SupportsOscillate = features.contains(.Oscillate) } } - + override var ComponentIcon: String { return "mdi:fan" } - + override class func ignoredProperties() -> [String] { return ["SupportedFeatures", "SupportsSetSpeed", "SupportsOscillate"] } @@ -44,7 +43,7 @@ class Fan: Entity { struct FanSupportedFeatures: OptionSet { let rawValue: Int - + static let SetSpeed = FanSupportedFeatures(rawValue: 1) static let Oscillate = FanSupportedFeatures(rawValue: 2) } diff --git a/HomeAssistant/Classes/Components/GarageDoorComponent.swift b/HomeAssistant/Classes/Components/GarageDoorComponent.swift index 499b7aa14..7d5682235 100644 --- a/HomeAssistant/Classes/Components/GarageDoorComponent.swift +++ b/HomeAssistant/Classes/Components/GarageDoorComponent.swift @@ -10,15 +10,15 @@ import Foundation import ObjectMapper class GarageDoor: Entity { - + dynamic var IsOpen: Bool = false - + override func mapping(map: Map) { super.mapping(map: map) - + IsOpen <- (map["state"], ComponentBoolTransform(trueValue: "open", falseValue: "closed")) } - + override var ComponentIcon: String { return "mdi:glassdoor" } diff --git a/HomeAssistant/Classes/Components/GroupComponent.swift b/HomeAssistant/Classes/Components/GroupComponent.swift index f95b0c8f9..8d076c166 100644 --- a/HomeAssistant/Classes/Components/GroupComponent.swift +++ b/HomeAssistant/Classes/Components/GroupComponent.swift @@ -20,35 +20,35 @@ let isAllGroupTransform = TransformOf(fromJSON: { (value: String?) }) class Group: Entity { - + dynamic var IsAllGroup: Bool = false dynamic var View: Bool = false dynamic var Auto: Bool = false var Order = RealmOptional() var Entities = List() dynamic var EntityIds = [String]() - + override func mapping(map: Map) { super.mapping(map: map) - + IsAllGroup <- (map["entity_id"], isAllGroupTransform) View <- map["attributes.view"] Auto <- map["attributes.auto"] Order.value <- map["attributes.order"] - + EntityIds <- map["attributes.entity_id"] - + EntityIds.forEach { entityId in let returning = Entity() returning.ID = entityId self.Entities.append(returning) } } - + override var ComponentIcon: String { return "mdi:google-circles-communities" } - + override class func ignoredProperties() -> [String] { return ["EntityIds"] } diff --git a/HomeAssistant/Classes/Components/InputBooleanComponent.swift b/HomeAssistant/Classes/Components/InputBooleanComponent.swift index a10c986ef..815992c17 100644 --- a/HomeAssistant/Classes/Components/InputBooleanComponent.swift +++ b/HomeAssistant/Classes/Components/InputBooleanComponent.swift @@ -13,7 +13,7 @@ class InputBoolean: SwitchableEntity { override func mapping(map: Map) { super.mapping(map: map) } - + override var ComponentIcon: String { return "mdi:drawing" } diff --git a/HomeAssistant/Classes/Components/InputSelectComponent.swift b/HomeAssistant/Classes/Components/InputSelectComponent.swift index ce1e0569d..e8a255471 100644 --- a/HomeAssistant/Classes/Components/InputSelectComponent.swift +++ b/HomeAssistant/Classes/Components/InputSelectComponent.swift @@ -11,12 +11,12 @@ import ObjectMapper import RealmSwift class InputSelect: Entity { - + let Options = List() - + override func mapping(map: Map) { super.mapping(map: map) - + var Options: [String]? = nil Options <- map["attributes.options"] Options?.forEach { option in @@ -25,7 +25,7 @@ class InputSelect: Entity { self.Options.append(value) } } - + override var ComponentIcon: String { return "mdi:format-list-bulleted" } diff --git a/HomeAssistant/Classes/Components/InputSlider.swift b/HomeAssistant/Classes/Components/InputSlider.swift index e2ed1a4ff..2bd9d3cce 100644 --- a/HomeAssistant/Classes/Components/InputSlider.swift +++ b/HomeAssistant/Classes/Components/InputSlider.swift @@ -11,23 +11,23 @@ import ObjectMapper import RealmSwift class InputSlider: Entity { - + var Minimum = RealmOptional() var Maximum = RealmOptional() var Step = RealmOptional() - + override func mapping(map: Map) { super.mapping(map: map) - + Maximum.value <- map["attributes.max"] Minimum.value <- map["attributes.min"] Step.value <- map["attributes.step"] } - + override var ComponentIcon: String { return "mdi:ray-vertex" } - + func SelectValue(_ value: Float) { let _ = HomeAssistantAPI.sharedInstance.CallService(domain: "input_slider", service: "select_value", serviceData: ["entity_id": self.ID as AnyObject, "value": value as AnyObject]) } diff --git a/HomeAssistant/Classes/Components/LightComponent.swift b/HomeAssistant/Classes/Components/LightComponent.swift index 3759abf01..1b99f3272 100644 --- a/HomeAssistant/Classes/Components/LightComponent.swift +++ b/HomeAssistant/Classes/Components/LightComponent.swift @@ -11,7 +11,7 @@ import ObjectMapper import RealmSwift class Light: SwitchableEntity { - + var Brightness = RealmOptional() var ColorTemp = RealmOptional() dynamic var RGBColor: [Int]? @@ -24,17 +24,16 @@ class Light: SwitchableEntity { dynamic var SupportsTransition: Bool = false dynamic var SupportsXYColor: Bool = false var SupportedFeatures: Int? - + override func mapping(map: Map) { super.mapping(map: map) - + Brightness.value <- map["attributes.brightness"] ColorTemp.value <- map["attributes.color_temp"] RGBColor <- map["attributes.rgb_color"] XYColor <- map["attributes.xy_color"] SupportedFeatures <- map["attributes.supported_features"] - - + if let supported = self.SupportedFeatures { let features = LightSupportedFeatures(rawValue: supported) self.SupportsBrightness = features.contains(.Brightness) @@ -46,7 +45,7 @@ class Light: SwitchableEntity { self.SupportsXYColor = features.contains(.XYColor) } } - + override func EntityColor() -> UIColor { if self.IsOn! { if self.RGBColor != nil { @@ -62,7 +61,7 @@ class Light: SwitchableEntity { return self.DefaultEntityUIColor } } - + override var ComponentIcon: String { return "mdi:lightbulb" } @@ -74,7 +73,7 @@ class Light: SwitchableEntity { struct LightSupportedFeatures: OptionSet { let rawValue: Int - + static let Brightness = LightSupportedFeatures(rawValue: 1) static let ColorTemp = LightSupportedFeatures(rawValue: 2) static let Effect = LightSupportedFeatures(rawValue: 4) diff --git a/HomeAssistant/Classes/Components/LockComponent.swift b/HomeAssistant/Classes/Components/LockComponent.swift index ed6a82f01..411d853ac 100644 --- a/HomeAssistant/Classes/Components/LockComponent.swift +++ b/HomeAssistant/Classes/Components/LockComponent.swift @@ -10,19 +10,19 @@ import Foundation import ObjectMapper class Lock: Entity { - + dynamic var IsLocked: Bool = false override func mapping(map: Map) { super.mapping(map: map) - + IsLocked <- (map["state"], ComponentBoolTransform(trueValue: "locked", falseValue: "unlocked")) } - + override var ComponentIcon: String { return "mdi:lock-open" } - + override func StateIcon() -> String { return (self.State == "unlocked") ? "mdi:lock-open" : "mdi:lock" } diff --git a/HomeAssistant/Classes/Components/MediaPlayerComponent.swift b/HomeAssistant/Classes/Components/MediaPlayerComponent.swift index 9321a9527..95c4bab8e 100644 --- a/HomeAssistant/Classes/Components/MediaPlayerComponent.swift +++ b/HomeAssistant/Classes/Components/MediaPlayerComponent.swift @@ -11,7 +11,7 @@ import ObjectMapper import RealmSwift class MediaPlayer: SwitchableEntity { - + dynamic var IsPlaying: Bool = false dynamic var IsIdle: Bool = false var IsVolumeMuted = RealmOptional() @@ -37,10 +37,10 @@ class MediaPlayer: SwitchableEntity { dynamic var SupportsStop: Bool = false dynamic var SupportsClearPlaylist: Bool = false var SupportedMediaCommands: Int? - + override func mapping(map: Map) { super.mapping(map: map) - + IsPlaying <- (map["state"], ComponentBoolTransform(trueValue: "playing", falseValue: "paused")) IsIdle <- (map["state"], ComponentBoolTransform(trueValue: "idle", falseValue: "")) IsVolumeMuted.value <- map["attributes.is_volume_muted"] @@ -51,7 +51,7 @@ class MediaPlayer: SwitchableEntity { Source <- map["attributes.source"] VolumeLevel.value <- map["attributes.volume_level"] SourceList <- map["attributes.source_list"] - + var StoredSourceList: [String]? = nil StoredSourceList <- map["attributes.source_list"] StoredSourceList?.forEach { option in @@ -59,10 +59,9 @@ class MediaPlayer: SwitchableEntity { value.value = option self.StoredSourceList.append(value) } - + SupportedMediaCommands <- map["attributes.supported_media_commands"] - - + if let supported = self.SupportedMediaCommands { let features = MediaPlayerSupportedCommands(rawValue: supported) self.SupportsPause = features.contains(.Pause) @@ -80,11 +79,11 @@ class MediaPlayer: SwitchableEntity { self.SupportsClearPlaylist = features.contains(.ClearPlaylist) } } - + override class func ignoredProperties() -> [String] { return ["SupportedMediaCommands", "SourceList", "SupportsPause", "SupportsSeek", "SupportsVolumeSet", "SupportsVolumeMute", "SupportsPreviousTrack", "SupportsNextTrack", "SupportsTurnOn", "SupportsTurnOff", "SupportsPlayMedia", "SupportsVolumeStep", "SupportsSelectSource", "SupportsStop", "SupportsClearPlaylist"] } - + func humanReadableMediaDuration() -> String { if let durationSeconds = self.MediaDuration.value { let hours = durationSeconds / 3600 @@ -95,7 +94,7 @@ class MediaPlayer: SwitchableEntity { return "00:00:00" } } - + func muteOn() { let _ = HomeAssistantAPI.sharedInstance.CallService(domain: "media_player", service: "volume_mute", serviceData: ["entity_id": self.ID as AnyObject, "is_volume_muted": "on" as AnyObject]) } @@ -106,11 +105,11 @@ class MediaPlayer: SwitchableEntity { let fixedVolume = newVolume/100 let _ = HomeAssistantAPI.sharedInstance.CallService(domain: "media_player", service: "volume_set", serviceData: ["entity_id": self.ID as AnyObject, "volume_level": fixedVolume as AnyObject]) } - + override var ComponentIcon: String { return "mdi:cast" } - + override func StateIcon() -> String { return (self.State != "off" && self.State != "idle") ? "mdi:cast-connected" : "mdi:cast" } @@ -118,7 +117,7 @@ class MediaPlayer: SwitchableEntity { struct MediaPlayerSupportedCommands: OptionSet { let rawValue: Int - + static let Pause = MediaPlayerSupportedCommands(rawValue: 1) static let Seek = MediaPlayerSupportedCommands(rawValue: 2) static let VolumeSet = MediaPlayerSupportedCommands(rawValue: 4) diff --git a/HomeAssistant/Classes/Components/SceneComponent.swift b/HomeAssistant/Classes/Components/SceneComponent.swift index bf6059c02..d31f5c1a2 100644 --- a/HomeAssistant/Classes/Components/SceneComponent.swift +++ b/HomeAssistant/Classes/Components/SceneComponent.swift @@ -11,26 +11,26 @@ import ObjectMapper import RealmSwift class Scene: Entity { - + var Entities = List() dynamic var EntityIds = [String]() - + override func mapping(map: Map) { super.mapping(map: map) - + EntityIds <- map["attributes.entity_id"] - + EntityIds.forEach { entityId in let returning = Entity() returning.ID = entityId self.Entities.append(returning) } } - + override var ComponentIcon: String { return "mdi:google-pages" } - + override class func ignoredProperties() -> [String] { return ["EntityIds"] } diff --git a/HomeAssistant/Classes/Components/ScriptComponent.swift b/HomeAssistant/Classes/Components/ScriptComponent.swift index a8375615e..a1c96aab7 100644 --- a/HomeAssistant/Classes/Components/ScriptComponent.swift +++ b/HomeAssistant/Classes/Components/ScriptComponent.swift @@ -10,15 +10,15 @@ import Foundation import ObjectMapper class Script: SwitchableEntity { - + dynamic var CanCancel: Bool = false - + override func mapping(map: Map) { super.mapping(map: map) - + CanCancel <- map["attributes.can_cancel"] } - + override var ComponentIcon: String { return "mdi:file-document" } diff --git a/HomeAssistant/Classes/Components/SensorComponent.swift b/HomeAssistant/Classes/Components/SensorComponent.swift index 6e3994aec..5d88cf63a 100644 --- a/HomeAssistant/Classes/Components/SensorComponent.swift +++ b/HomeAssistant/Classes/Components/SensorComponent.swift @@ -10,17 +10,17 @@ import Foundation import ObjectMapper class Sensor: Entity { - + dynamic var SensorClass: String? = nil override func mapping(map: Map) { super.mapping(map: map) - + SensorClass <- map["attributes.sensor_class"] } - + override var ComponentIcon: String { return "mdi:eye" } - + } diff --git a/HomeAssistant/Classes/Components/SunComponent.swift b/HomeAssistant/Classes/Components/SunComponent.swift index ab2918445..23db7281f 100644 --- a/HomeAssistant/Classes/Components/SunComponent.swift +++ b/HomeAssistant/Classes/Components/SunComponent.swift @@ -11,23 +11,23 @@ import ObjectMapper import RealmSwift class Sun: Entity { - + var Elevation = RealmOptional() var NextRising: Date? = nil var NextSetting: Date? = nil - + override func mapping(map: Map) { super.mapping(map: map) - + Elevation.value <- map["attributes.elevation"] NextRising <- (map["attributes.next_rising"], HomeAssistantTimestampTransform()) NextSetting <- (map["attributes.next_setting"], HomeAssistantTimestampTransform()) } - + override func EntityColor() -> UIColor { return self.State == "above_horizon" ? colorWithHexString("#DCC91F", alpha: 1) : self.DefaultEntityUIColor } - + override var ComponentIcon: String { return "mdi:white-balance-sunny" } diff --git a/HomeAssistant/Classes/Components/SwitchComponent.swift b/HomeAssistant/Classes/Components/SwitchComponent.swift index e8d10580f..f795b1f01 100644 --- a/HomeAssistant/Classes/Components/SwitchComponent.swift +++ b/HomeAssistant/Classes/Components/SwitchComponent.swift @@ -11,17 +11,17 @@ import ObjectMapper import RealmSwift class Switch: SwitchableEntity { - + var TodayMilliwattHours = RealmOptional() var CurrentPowerMilliwattHours = RealmOptional() - + override func mapping(map: Map) { super.mapping(map: map) - + TodayMilliwattHours.value <- map["attributes.today_mwh"] CurrentPowerMilliwattHours.value <- map["attributes.current_power_mwh"] } - + override var ComponentIcon: String { return "mdi:flash" } diff --git a/HomeAssistant/Classes/Components/ThermostatComponent.swift b/HomeAssistant/Classes/Components/ThermostatComponent.swift index 2864d6b9e..5f47e5f24 100644 --- a/HomeAssistant/Classes/Components/ThermostatComponent.swift +++ b/HomeAssistant/Classes/Components/ThermostatComponent.swift @@ -10,7 +10,7 @@ import Foundation import ObjectMapper class Thermostat: Entity { - + var AwayMode: Bool? var CurrentTemperature: Int? var Fan: Bool? @@ -19,10 +19,10 @@ class Thermostat: Entity { var TargetTemperatureHigh: Int? var TargetTemperatureLow: Int? var Temperature: Int? - + override func mapping(map: Map) { super.mapping(map: map) - + AwayMode <- (map["attributes.away_mode"], ComponentBoolTransform(trueValue: "on", falseValue: "off")) CurrentTemperature <- map["attributes.current_temperature"] Fan <- (map["attributes.fan"], ComponentBoolTransform(trueValue: "on", falseValue: "off")) @@ -47,7 +47,7 @@ class Thermostat: Entity { func setTemperature(_ newTemp: Float) { let _ = HomeAssistantAPI.sharedInstance.CallService(domain: "thermostat", service: "set_temperature", serviceData: ["entity_id": self.ID as AnyObject, "temperature": newTemp as AnyObject]) } - + override var ComponentIcon: String { return "mdi:nest-thermostat" } diff --git a/HomeAssistant/Classes/Components/WeblinkComponent.swift b/HomeAssistant/Classes/Components/WeblinkComponent.swift index 3109c76a0..699be3f1c 100644 --- a/HomeAssistant/Classes/Components/WeblinkComponent.swift +++ b/HomeAssistant/Classes/Components/WeblinkComponent.swift @@ -10,15 +10,15 @@ import Foundation import ObjectMapper class Weblink: Entity { - + var URL: String? - + override func mapping(map: Map) { super.mapping(map: map) - + URL <- map["attributes.url"] } - + override var ComponentIcon: String { return "mdi:open-in-new" } diff --git a/HomeAssistant/Classes/Components/ZoneComponent.swift b/HomeAssistant/Classes/Components/ZoneComponent.swift index b4006259e..6ce797fa2 100644 --- a/HomeAssistant/Classes/Components/ZoneComponent.swift +++ b/HomeAssistant/Classes/Components/ZoneComponent.swift @@ -11,26 +11,26 @@ import ObjectMapper import CoreLocation class Zone: Entity { - - dynamic var Latitude:Double = 0.0 - dynamic var Longitude:Double = 0.0 - dynamic var Radius:Double = 0.0 + + dynamic var Latitude: Double = 0.0 + dynamic var Longitude: Double = 0.0 + dynamic var Radius: Double = 0.0 dynamic var trackingEnabled = true dynamic var enterNotification = true dynamic var exitNotification = true - + override func mapping(map: Map) { super.mapping(map: map) - + Latitude <- map["attributes.latitude"] Longitude <- map["attributes.longitude"] Radius <- map["attributes.radius"] } - + func locationCoordinates() -> CLLocationCoordinate2D { return CLLocationCoordinate2D(latitude: CLLocationDegrees(self.Latitude), longitude: CLLocationDegrees(self.Longitude)) } - + func location() -> CLLocation { return CLLocation(coordinate: self.locationCoordinates(), altitude: 0, horizontalAccuracy: self.Radius, verticalAccuracy: -1, timestamp: Date()) } diff --git a/HomeAssistant/Classes/Entity.swift b/HomeAssistant/Classes/Entity.swift index 863f4f72c..1d173e76f 100644 --- a/HomeAssistant/Classes/Entity.swift +++ b/HomeAssistant/Classes/Entity.swift @@ -13,7 +13,7 @@ import Realm class Entity: Object, StaticMappable { let DefaultEntityUIColor = colorWithHexString("#44739E", alpha: 1) - + dynamic var ID: String = "" dynamic var State: String = "" dynamic var Attributes: [String:Any] { @@ -28,7 +28,7 @@ class Entity: Object, StaticMappable { return [String: Any]() } } - + set { do { let data = try JSONSerialization.data(withJSONObject: newValue, options: []) @@ -49,12 +49,12 @@ class Entity: Object, StaticMappable { dynamic var LastChanged: Date? = nil dynamic var LastUpdated: Date? = nil // let Groups = LinkingObjects(fromType: Group.self, property: "Entities") - + // Z-Wave properties dynamic var Location: String? = nil dynamic var NodeID: String? = nil var BatteryLevel = RealmOptional() - + class func objectForMapping(map: Map) -> BaseMappable? { if let entityId: String = map["entity_id"].value() { let entityType = entityId.components(separatedBy: ".")[0] @@ -121,12 +121,12 @@ class Entity: Object, StaticMappable { UnitOfMeasurement <- map["attributes.unit_of_measurement"] LastChanged <- (map["last_changed"], HomeAssistantTimestampTransform()) LastUpdated <- (map["last_updated"], HomeAssistantTimestampTransform()) - + // Z-Wave properties NodeID <- map["attributes.node_id"] Location <- map["attributes.location"] BatteryLevel.value <- map["attributes.battery_level"] - + if let pic = self.Picture { HomeAssistantAPI.sharedInstance.getImage(imageUrl: pic).then { image -> Void in self.DownloadedPicture = image @@ -135,28 +135,28 @@ class Entity: Object, StaticMappable { } } } - + override class func ignoredProperties() -> [String] { return ["Attributes", "DownloadedPicture"] } - + override static func primaryKey() -> String? { return "ID" } - + func turnOn() { let _ = HomeAssistantAPI.sharedInstance.turnOnEntity(entity: self) } - + func turnOff() { let _ = HomeAssistantAPI.sharedInstance.turnOffEntity(entity: self) } - + func toggle() { let _ = HomeAssistantAPI.sharedInstance.toggleEntity(entity: self) } - - var ComponentIcon : String { + + var ComponentIcon: String { switch (self.Domain) { case "alarm_control_panel": return "mdi:bell" @@ -227,7 +227,7 @@ class Entity: Object, StaticMappable { return "mdi:bookmark" } } - + func StateIcon() -> String { if self.MobileIcon != nil { return self.MobileIcon! } if self.Icon != nil { return self.Icon! } @@ -261,28 +261,28 @@ class Entity: Object, StaticMappable { return colorWithHexString(hexColor, alpha: 1) } } - + var EntityIcon: UIImage { return getIconForIdentifier(self.StateIcon(), iconWidth: 30, iconHeight: 30, color: self.EntityColor()) } - + func EntityIcon(width: Double, height: Double, color: UIColor) -> UIImage { return getIconForIdentifier(self.StateIcon(), iconWidth: width, iconHeight: height, color: color) } - - var Name : String { + + var Name: String { if let friendly = self.FriendlyName { return friendly } else { return self.ID.replacingOccurrences(of: "\(self.Domain).", with: "").replacingOccurrences(of: "_", with: " ").capitalized } } - - var CleanedState : String { + + var CleanedState: String { return self.State.replacingOccurrences(of: "_", with: " ").capitalized } - - var Domain : String { + + var Domain: String { return self.ID.components(separatedBy: ".")[0] } } @@ -292,7 +292,7 @@ open class StringObject: Object { } open class HomeAssistantTimestampTransform: DateFormatterTransform { - + public init() { let formatter = DateFormatter() formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") as Locale! @@ -302,28 +302,28 @@ open class HomeAssistantTimestampTransform: DateFormatterTransform { } else { formatter.timeZone = TimeZone.autoupdatingCurrent } - + super.init(dateFormatter: formatter) } } open class ComponentBoolTransform: TransformType { - + public typealias Object = Bool public typealias JSON = String - + let trueValue: String let falseValue: String - + public init(trueValue: String, falseValue: String) { self.trueValue = trueValue self.falseValue = falseValue } - + public func transformFromJSON(_ value: Any?) -> Bool? { return ((value! as! String) == self.trueValue) } - + open func transformToJSON(_ value: Bool?) -> String? { return (value == true) ? self.trueValue : self.falseValue } diff --git a/HomeAssistant/Classes/HA API Responses/Beacons.swift b/HomeAssistant/Classes/HA API Responses/Beacons.swift index 469f8e095..74f09d4ae 100644 --- a/HomeAssistant/Classes/HA API Responses/Beacons.swift +++ b/HomeAssistant/Classes/HA API Responses/Beacons.swift @@ -17,11 +17,11 @@ class Beacon: Mappable { var Major: Int? var Minor: Int? var Radius: Int? - - required init?(map: Map){ - + + required init?(map: Map) { + } - + func mapping(map: Map) { Name <- map["name"] Zone <- map["zone"] diff --git a/HomeAssistant/Classes/HA API Responses/Bootstrap.swift b/HomeAssistant/Classes/HA API Responses/Bootstrap.swift index c3446ee8b..d0ced3962 100644 --- a/HomeAssistant/Classes/HA API Responses/Bootstrap.swift +++ b/HomeAssistant/Classes/HA API Responses/Bootstrap.swift @@ -19,4 +19,4 @@ import Foundation // Message <- map["message"] // IsOK <- (map["message"] == "API running.") // } -//} \ No newline at end of file +//} diff --git a/HomeAssistant/Classes/HA API Responses/Config.swift b/HomeAssistant/Classes/HA API Responses/Config.swift index 00ceb3f64..25cdf2a04 100644 --- a/HomeAssistant/Classes/HA API Responses/Config.swift +++ b/HomeAssistant/Classes/HA API Responses/Config.swift @@ -13,31 +13,31 @@ class ConfigResponse: Mappable { var Components: [String]? var Version: String? var ConfigDirectory: String? - + var TemperatureUnit: String? var LengthUnit: String? var MassUnit: String? var VolumeUnit: String? - + var LocationName: String? var Timezone: String? var Latitude: Float? var Longitude: Float? - - required init?(map: Map){ - + + required init?(map: Map) { + } - + func mapping(map: Map) { Components <- map["components"] Version <- map["version"] ConfigDirectory <- map["config_dir"] - + TemperatureUnit <- map["unit_system.temperature"] LengthUnit <- map["unit_system.length"] MassUnit <- map["unit_system.mass"] VolumeUnit <- map["unit_system.volume"] - + LocationName <- map["location_name"] Timezone <- map["time_zone"] Latitude <- map["latitude"] diff --git a/HomeAssistant/Classes/HA API Responses/DiscoveryInfo.swift b/HomeAssistant/Classes/HA API Responses/DiscoveryInfo.swift index 81ebc651d..809ea7c53 100644 --- a/HomeAssistant/Classes/HA API Responses/DiscoveryInfo.swift +++ b/HomeAssistant/Classes/HA API Responses/DiscoveryInfo.swift @@ -23,17 +23,17 @@ class DiscoveryInfoResponse: Mappable { var Version: String = "" var UsesSSL: Bool = false - required init?(map: Map){ - + required init?(map: Map) { + } - + func mapping(map: Map) { BaseURL <- (map["base_url"], URLTransform()) BaseURLString <- map["base_url"] LocationName <- map["location_name"] RequiresPassword <- map["requires_api_password"] Version <- map["version"] - + UsesSSL <- (map["base_url"], usesSSL) } } diff --git a/HomeAssistant/Classes/HA API Responses/Events.swift b/HomeAssistant/Classes/HA API Responses/Events.swift index e85b47475..d4c495582 100644 --- a/HomeAssistant/Classes/HA API Responses/Events.swift +++ b/HomeAssistant/Classes/HA API Responses/Events.swift @@ -12,11 +12,11 @@ import ObjectMapper class EventsResponse: Mappable { var Event: String? var ListenerCount: Int? - - required init?(map: Map){ - + + required init?(map: Map) { + } - + func mapping(map: Map) { Event <- map["event"] ListenerCount <- map["listener_count"] diff --git a/HomeAssistant/Classes/HA API Responses/History.swift b/HomeAssistant/Classes/HA API Responses/History.swift index d6b66d510..f23391bf3 100644 --- a/HomeAssistant/Classes/HA API Responses/History.swift +++ b/HomeAssistant/Classes/HA API Responses/History.swift @@ -15,10 +15,10 @@ class HistoryResponse: Mappable { // var Domain: String? var Entities: [HistoryGroup]? - required init?(map: Map){ + required init?(map: Map) { print("MAP", map) } - + func mapping(map: Map) { print("map", map) Entities <- map @@ -29,13 +29,13 @@ class HistoryResponse: Mappable { } class HistoryGroup: Mappable { - + var Events: [Entity]? - - required init?(map: Map){ + + required init?(map: Map) { print("MAP", map) } - + func mapping(map: Map) { print("map", map) Events <- map diff --git a/HomeAssistant/Classes/HA API Responses/PushConfiguration.swift b/HomeAssistant/Classes/HA API Responses/PushConfiguration.swift index bf4faf06a..15bd06d4e 100644 --- a/HomeAssistant/Classes/HA API Responses/PushConfiguration.swift +++ b/HomeAssistant/Classes/HA API Responses/PushConfiguration.swift @@ -11,11 +11,11 @@ import ObjectMapper class PushConfiguration: Mappable { var Categories: [PushCategory]? - - required init?(map: Map){ - + + required init?(map: Map) { + } - + func mapping(map: Map) { Categories <- map["categories"] } @@ -24,13 +24,13 @@ class PushConfiguration: Mappable { class PushCategory: Mappable { var Name: String? var Identifier: String? - + var Actions: [PushAction]? - - required init?(map: Map){ - + + required init?(map: Map) { + } - + func mapping(map: Map) { Name <- map["name"] Identifier <- map["identifier"] @@ -47,11 +47,11 @@ class PushAction: Mappable { var Destructive: Bool = false var TextInputButtonTitle: String? var TextInputPlaceholder: String? - - required init?(map: Map){ - + + required init?(map: Map) { + } - + func mapping(map: Map) { Title <- map["title"] Identifier <- map["identifier"] diff --git a/HomeAssistant/Classes/HA API Responses/SSE/CallService.swift b/HomeAssistant/Classes/HA API Responses/SSE/CallService.swift index c0a77810b..70c1c5a45 100644 --- a/HomeAssistant/Classes/HA API Responses/SSE/CallService.swift +++ b/HomeAssistant/Classes/HA API Responses/SSE/CallService.swift @@ -14,7 +14,7 @@ class CallServiceEvent: SSEEvent { var Domain: String? var ServiceCallID: String? var ServiceData: [String:AnyObject] = [:] - + override func mapping(map: Map) { super.mapping(map: map) Service <- map["data.service"] diff --git a/HomeAssistant/Classes/HA API Responses/SSE/Event.swift b/HomeAssistant/Classes/HA API Responses/SSE/Event.swift index 239b9e620..571b5f26e 100644 --- a/HomeAssistant/Classes/HA API Responses/SSE/Event.swift +++ b/HomeAssistant/Classes/HA API Responses/SSE/Event.swift @@ -13,9 +13,9 @@ class SSEEvent: StaticMappable { var EventType: String = "" var TimeFired: Date? var Origin: String? - - init(){} - + + init() {} + public static func objectForMapping(map: Map) -> BaseMappable? { if let eventType: String = map["event_type"].value() { switch eventType { @@ -32,7 +32,7 @@ class SSEEvent: StaticMappable { } return nil } - + func mapping(map: Map) { EventType <- map["event_type"] TimeFired <- (map["time_fired"], HomeAssistantTimestampTransform()) diff --git a/HomeAssistant/Classes/HA API Responses/SSE/ServiceExecuted.swift b/HomeAssistant/Classes/HA API Responses/SSE/ServiceExecuted.swift index f80003b51..f570769a6 100644 --- a/HomeAssistant/Classes/HA API Responses/SSE/ServiceExecuted.swift +++ b/HomeAssistant/Classes/HA API Responses/SSE/ServiceExecuted.swift @@ -11,7 +11,7 @@ import ObjectMapper class ServiceExecutedEvent: SSEEvent { var ServiceCallID: String? - + override func mapping(map: Map) { super.mapping(map: map) ServiceCallID <- map["data.service_call_id"] diff --git a/HomeAssistant/Classes/HA API Responses/SSE/StateChanged.swift b/HomeAssistant/Classes/HA API Responses/SSE/StateChanged.swift index f04542ab3..6f3518019 100644 --- a/HomeAssistant/Classes/HA API Responses/SSE/StateChanged.swift +++ b/HomeAssistant/Classes/HA API Responses/SSE/StateChanged.swift @@ -14,7 +14,7 @@ class StateChangedEvent: SSEEvent { var OldState: Entity? var EntityID: String? var EntityDomain: String? - + override func mapping(map: Map) { super.mapping(map: map) NewState <- map["data.new_state"] @@ -27,16 +27,16 @@ class StateChangedEvent: SSEEvent { open class EntityIDToDomainTransform: TransformType { public typealias Object = String public typealias JSON = String - + public init() {} - + public func transformFromJSON(_ value: Any?) -> String? { if let entityId = value as? String { return entityId.components(separatedBy: ".")[0] } return nil } - + open func transformToJSON(_ value: String?) -> String? { return nil } diff --git a/HomeAssistant/Classes/HA API Responses/Services.swift b/HomeAssistant/Classes/HA API Responses/Services.swift index e53c490fd..333bbe4d4 100644 --- a/HomeAssistant/Classes/HA API Responses/Services.swift +++ b/HomeAssistant/Classes/HA API Responses/Services.swift @@ -12,11 +12,11 @@ import ObjectMapper class ServicesResponse: Mappable { var Domain: String? var Services: [String : ServiceDefinition] = [:] - - required init?(map: Map){ - + + required init?(map: Map) { + } - + func mapping(map: Map) { Domain <- map["domain"] Services <- map["services"] @@ -26,11 +26,11 @@ class ServicesResponse: Mappable { class ServiceDefinition: Mappable { var Description: String? var Fields: [String : ServiceField] = [:] - - required init?(map: Map){ - + + required init?(map: Map) { + } - + func mapping(map: Map) { Description <- map["description"] Fields <- map["fields"] @@ -40,11 +40,11 @@ class ServiceDefinition: Mappable { class ServiceField: Mappable { var Description: String? var Example: AnyObject? - - required init?(map: Map){ - + + required init?(map: Map) { + } - + func mapping(map: Map) { Description <- map["description"] Example <- map["example"] diff --git a/HomeAssistant/Classes/HA API Responses/Status.swift b/HomeAssistant/Classes/HA API Responses/Status.swift index 7dbb309e3..d33b56102 100644 --- a/HomeAssistant/Classes/HA API Responses/Status.swift +++ b/HomeAssistant/Classes/HA API Responses/Status.swift @@ -22,16 +22,15 @@ let isOKTransform = TransformOf(fromJSON: { (value: String?) -> Bo return nil }) - class StatusResponse: Mappable { var Result: String? var Message: String? var IsOK: Bool? - - required init?(map: Map){ - + + required init?(map: Map) { + } - + func mapping(map: Map) { Result <- map["result"] Message <- map["message"] diff --git a/HomeAssistant/Classes/IdentifyRequest.swift b/HomeAssistant/Classes/IdentifyRequest.swift index 8881ceaa1..dfea8cd6f 100644 --- a/HomeAssistant/Classes/IdentifyRequest.swift +++ b/HomeAssistant/Classes/IdentifyRequest.swift @@ -27,13 +27,13 @@ class IdentifyRequest: Mappable { var PushToken: String? var BatteryLevel: Int? var BatteryState: String? - + init() {} - - required init?(map: Map){ - + + required init?(map: Map) { + } - + func mapping(map: Map) { AppBuildNumber <- map["app.buildNumber"] AppBundleIdentifer <- map["app.bundleIdentifer"] diff --git a/HomeAssistant/Classes/PushRegistrationRequest.swift b/HomeAssistant/Classes/PushRegistrationRequest.swift index f255211fc..34bb15158 100644 --- a/HomeAssistant/Classes/PushRegistrationRequest.swift +++ b/HomeAssistant/Classes/PushRegistrationRequest.swift @@ -27,15 +27,15 @@ class PushRegistrationRequest: Mappable { var UserEmail: String? var HomeAssistantVersion: String? var HomeAssistantTimezone: String? - + var APNSSandbox: Bool = false - + init() {} - - required init?(map: Map){ - + + required init?(map: Map) { + } - + func mapping(map: Map) { AppBuildNumber <- map["appBuildNumber"] AppBundleIdentifer <- map["appBundleIdentifer"] diff --git a/HomeAssistant/Classes/PushRegistrationResponse.swift b/HomeAssistant/Classes/PushRegistrationResponse.swift index 15ba0abeb..8fd375599 100644 --- a/HomeAssistant/Classes/PushRegistrationResponse.swift +++ b/HomeAssistant/Classes/PushRegistrationResponse.swift @@ -32,13 +32,13 @@ class PushRegistrationResponse: Mappable { var SNSPlatform: String? var SubscriptionARN: String? var UserEmail: String? - + init() {} - - required init?(map: Map){ - + + required init?(map: Map) { + } - + func mapping(map: Map) { APNSSandbox <- map["registration.apnsSandbox"] AppBuildNumber <- map["registration.appBuildNumber"] diff --git a/HomeAssistant/Classes/SwitchableEntity.swift b/HomeAssistant/Classes/SwitchableEntity.swift index 7e5221b64..79b1fd34a 100644 --- a/HomeAssistant/Classes/SwitchableEntity.swift +++ b/HomeAssistant/Classes/SwitchableEntity.swift @@ -12,15 +12,15 @@ import Realm import RealmSwift class SwitchableEntity: Entity { - + var IsOn: Bool? - + override func mapping(map: Map) { super.mapping(map: map) - + IsOn <- (map["state"], ComponentBoolTransform(trueValue: "on", falseValue: "off")) } - + override func EntityColor() -> UIColor { return self.State == "on" ? colorWithHexString("#DCC91F", alpha: 1) : self.DefaultEntityUIColor } diff --git a/HomeAssistant/HAAPI.swift b/HomeAssistant/HAAPI.swift index 57180a687..f05de0298 100644 --- a/HomeAssistant/HAAPI.swift +++ b/HomeAssistant/HAAPI.swift @@ -27,68 +27,68 @@ let prefs = UserDefaults(suiteName: "group.io.robbie.homeassistant")! let APIClientSharedInstance = HomeAssistantAPI() public class HomeAssistantAPI { - - class var sharedInstance:HomeAssistantAPI { + + class var sharedInstance: HomeAssistantAPI { get { - return APIClientSharedInstance; + return APIClientSharedInstance } } - - private var manager : Alamofire.SessionManager? - - var baseAPIURL : String = "" - var apiPassword : String = "" - - var deviceID : String = "" - var pushID : String = "" - var deviceToken : String = "" - + + private var manager: Alamofire.SessionManager? + + var baseAPIURL: String = "" + var apiPassword: String = "" + + var deviceID: String = "" + var pushID: String = "" + var deviceToken: String = "" + var eventSource: EventSource? = nil - - var mostRecentlySentMessage : String = String() - + + var mostRecentlySentMessage: String = String() + var services = [NetService]() - - var headers = [String:String]() - + + var headers = [String: String]() + var loadedComponents = [String]() - + let Location = LocationManager() - + func Setup(baseAPIUrl: String, APIPassword: String) -> Promise { self.baseAPIURL = baseAPIUrl+"/api/" self.apiPassword = APIPassword if apiPassword != "" { headers["X-HA-Access"] = apiPassword } - - var defaultHeaders = Alamofire.SessionManager.defaultHTTPHeaders + + var defaultHeaders = Alamofire.SessionManager.defaultHTTPHeaders for (header, value) in headers { defaultHeaders[header] = value } - + let configuration = URLSessionConfiguration.default configuration.httpAdditionalHeaders = defaultHeaders configuration.timeoutIntervalForRequest = 3 // seconds - + self.manager = Alamofire.SessionManager(configuration: configuration) - + if let deviceId = prefs.string(forKey: "deviceId") { deviceID = deviceId } - + if let pushId = prefs.string(forKey: "pushID") { pushID = pushId } - + if let deviceTok = prefs.string(forKey: "deviceToken") { deviceToken = deviceTok } - + return GetStatus() - + } - + func Connect() -> Promise { return Promise { fulfill, reject in GetConfig().then { config -> Void in @@ -103,24 +103,24 @@ public class HomeAssistantAPI { prefs.setValue(config.VolumeUnit, forKey: "volume_unit") prefs.setValue(config.Timezone, forKey: "time_zone") prefs.setValue(config.Version, forKey: "version") - + Crashlytics.sharedInstance().setObjectValue(config.Version, forKey: "hass_version") Crashlytics.sharedInstance().setObjectValue(self.loadedComponents.joined(separator: ","), forKey: "loadedComponents") Crashlytics.sharedInstance().setObjectValue(self.enabledPermissions.joined(separator: ","), forKey: "allowedPermissions") - + NotificationCenter.default.post(name: NSNotification.Name(rawValue: "connected"), object: nil, userInfo: nil) - + let _ = self.GetStates() - + if self.locationEnabled { self.trackLocation() } - + if self.loadedComponents.contains("ios") { CLSLogv("iOS component loaded, attempting identify", getVaList([])) _ = self.identifyDevice() } - + // self.GetHistory() self.startStream() fulfill(config) @@ -132,16 +132,16 @@ public class HomeAssistantAPI { } } - + func startStream() { eventSource = EventSource(url: baseAPIURL+"stream", headers: headers) - + eventSource?.onOpen { print("SSE: Connection Opened") self.showMurmur(title: "Connected to Home Assistant") NotificationCenter.default.post(name: NSNotification.Name(rawValue: "sse.opened"), object: nil, userInfo: nil) } - + eventSource?.onError { error in if let err = error { Crashlytics.sharedInstance().recordError(err) @@ -150,8 +150,8 @@ public class HomeAssistantAPI { NotificationCenter.default.post(name: NSNotification.Name(rawValue: "sse.error"), object: nil, userInfo: ["code": err.code, "description": err.description]) } } - - eventSource?.onMessage { (id, eventName, data) in + + eventSource?.onMessage { (_, eventName, data) in if let eventData = data { if eventData == "ping" { return } if let event = Mapper().map(JSONString: eventData) { @@ -169,10 +169,10 @@ public class HomeAssistantAPI { } } } - + func submitLocation(updateType: LocationUpdateTypes, coordinates: CLLocationCoordinate2D, accuracy: CLLocationAccuracy, zone: Zone? = nil) { UIDevice.current.isBatteryMonitoringEnabled = true - + var batteryState = "Unplugged" switch UIDevice.current.batteryState { case .unknown: @@ -184,8 +184,8 @@ public class HomeAssistantAPI { case .full: batteryState = "Full" } - - let locationUpdate : [String:Any] = [ + + let locationUpdate: [String:Any] = [ "battery": Int(UIDevice.current.batteryLevel*100), "battery_status": batteryState, "gps": [coordinates.latitude, coordinates.longitude], @@ -193,20 +193,20 @@ public class HomeAssistantAPI { "hostname": UIDevice().name, "dev_id": deviceID ] - + self.CallService(domain: "device_tracker", service: "see", serviceData: locationUpdate as [String : Any]).then {_ in print("Device seen!") }.catch {err in Crashlytics.sharedInstance().recordError(err as NSError) } - + UIDevice.current.isBatteryMonitoringEnabled = false - + let notificationTitle = "Location change" var notificationBody = "" var notificationIdentifer = "" var shouldNotify = false - + switch updateType { case .RegionEnter: notificationBody = "\(zone!.Name) entered" @@ -223,14 +223,14 @@ public class HomeAssistantAPI { default: notificationBody = "" } - + if shouldNotify { if #available(iOS 10, *) { let content = UNMutableNotificationContent() content.title = notificationTitle content.body = notificationBody content.sound = UNNotificationSound.default() - + UNUserNotificationCenter.current().add(UNNotificationRequest.init(identifier: notificationIdentifer, content: content, trigger: nil)) } else { let notification = UILocalNotification() @@ -244,17 +244,17 @@ public class HomeAssistantAPI { } } - + func trackLocation() { let _ = Location.getLocation(withAccuracy: .neighborhood, frequency: .significant, timeout: 50, onSuccess: { (location) in // You will receive at max one event if desidered accuracy can be achieved; this because you have set .OneShot as frequency. self.submitLocation(updateType: .Manual, coordinates: location.coordinate, accuracy: location.horizontalAccuracy, zone: nil) - }) { (lastValidLocation, error) in + }) { (_, error) in // something went wrong. request will be cancelled automatically print("Something went wrong when trying to get significant location updates! Error was:", error) Crashlytics.sharedInstance().recordError((error as Any) as! NSError) } - + for zone in realm.objects(Zone.self) { if zone.trackingEnabled == false { print("Skipping zone set to not track!") @@ -278,7 +278,7 @@ public class HomeAssistantAPI { } // let location = Location() - + // self.getBeacons().then { beacons -> Void in // for beacon in beacons { // print("Got beacon from HA", beacon.UUID, beacon.Major, beacon.Minor) @@ -296,20 +296,20 @@ public class HomeAssistantAPI { // } } - + func sendOneshotLocation() -> Promise { return Promise { fulfill, reject in let _ = Location.getLocation(withAccuracy: .neighborhood, frequency: .oneShot, timeout: 50, onSuccess: { (location) in self.submitLocation(updateType: .Manual, coordinates: location.coordinate, accuracy: location.horizontalAccuracy, zone: nil) fulfill(true) - }) { (lastValidLocation, error) in + }) { (_, error) in print("Error when trying to get a oneshot location!", error) Crashlytics.sharedInstance().recordError((error as Any) as! NSError) reject(error) } } } - + func GetStatus() -> Promise { let queryUrl = baseAPIURL return Promise { fulfill, reject in @@ -325,7 +325,7 @@ public class HomeAssistantAPI { } } } - + func GetConfig() -> Promise { let queryUrl = baseAPIURL+"config" return Promise { fulfill, reject in @@ -341,7 +341,7 @@ public class HomeAssistantAPI { } } } - + func GetServices() -> Promise<[ServicesResponse]> { let queryUrl = baseAPIURL+"services" return Promise { fulfill, reject in @@ -357,7 +357,7 @@ public class HomeAssistantAPI { } } } - + // func GetHistory() -> Promise { // let queryUrl = baseAPIURL+"history/period?filter_entity_id=sensor.uberpool_time" // return Promise { fulfill, reject in @@ -376,7 +376,7 @@ public class HomeAssistantAPI { // } // } // } - + func storeEntities(entities: [Entity]) { for entity in entities { try! realm.write { @@ -434,7 +434,7 @@ public class HomeAssistantAPI { } } } - + func GetStates() -> Promise<[Entity]> { let queryUrl = baseAPIURL+"states" return Promise { fulfill, reject in @@ -451,7 +451,7 @@ public class HomeAssistantAPI { } } } - + func GetStateForEntityIdMapped(entityId: String) -> Promise { let queryUrl = baseAPIURL+"states/"+entityId return Promise { fulfill, reject in @@ -468,7 +468,7 @@ public class HomeAssistantAPI { } } } - + func GetErrorLog() -> Promise { let queryUrl = baseAPIURL+"error_log" return Promise { fulfill, reject in @@ -484,7 +484,7 @@ public class HomeAssistantAPI { } } } - + func SetState(entityId: String, state: String) -> Promise { let queryUrl = baseAPIURL+"states/"+entityId return Promise { fulfill, reject in @@ -502,7 +502,7 @@ public class HomeAssistantAPI { } } } - + func CreateEvent(eventType: String, eventData: [String:Any]) -> Promise { let queryUrl = baseAPIURL+"events/"+eventType return Promise { fulfill, reject in @@ -521,7 +521,7 @@ public class HomeAssistantAPI { } } } - + func CallService(domain: String, service: String, serviceData: [String:Any]) -> Promise<[ServicesResponse]> { // self.showMurmur(title: domain+"/"+service+" called") let queryUrl = baseAPIURL+"services/"+domain+"/"+service @@ -538,41 +538,41 @@ public class HomeAssistantAPI { } } } - + func turnOn(entityId: String) -> Promise<[ServicesResponse]> { self.showMurmur(title: entityId+" turned on") return CallService(domain: "homeassistant", service: "turn_on", serviceData: ["entity_id": entityId]) } - + func turnOnEntity(entity: Entity) -> Promise<[ServicesResponse]> { self.showMurmur(title: "\(entity.Name) turned on") return CallService(domain: "homeassistant", service: "turn_on", serviceData: ["entity_id": entity.ID]) } - + func turnOff(entityId: String) -> Promise<[ServicesResponse]> { self.showMurmur(title: entityId+" turned off") return CallService(domain: "homeassistant", service: "turn_off", serviceData: ["entity_id": entityId]) } - + func turnOffEntity(entity: Entity) -> Promise<[ServicesResponse]> { self.showMurmur(title: "\(entity.Name) turned off") return CallService(domain: "homeassistant", service: "turn_off", serviceData: ["entity_id": entity.ID]) } - + func toggle(entityId: String) -> Promise<[ServicesResponse]> { let entity = realm.object(ofType: Entity.self, forPrimaryKey: entityId) self.showMurmur(title: "\(entity!.Name) toggled") return CallService(domain: "homeassistant", service: "toggle", serviceData: ["entity_id": entityId]) } - + func toggleEntity(entity: Entity) -> Promise<[ServicesResponse]> { self.showMurmur(title: "\(entity.Name) toggled") return CallService(domain: "homeassistant", service: "toggle", serviceData: ["entity_id": entity.ID]) } - + func buildIdentifyDict() -> [String:Any] { let deviceKitDevice = Device() - + let ident = IdentifyRequest() ident.AppBuildNumber = Int(string: Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion")! as! String) ident.AppBundleIdentifer = Bundle.main.bundleIdentifier @@ -589,9 +589,9 @@ public class HomeAssistantAPI { ident.PushID = pushID ident.PushSounds = listAllInstalledPushNotificationSounds() ident.PushToken = deviceToken - + UIDevice.current.isBatteryMonitoringEnabled = true - + switch UIDevice.current.batteryState { case .unknown: ident.BatteryState = "Unknown" @@ -602,17 +602,17 @@ public class HomeAssistantAPI { case .full: ident.BatteryState = "Full" } - + ident.BatteryLevel = Int(UIDevice.current.batteryLevel*100) - + UIDevice.current.isBatteryMonitoringEnabled = false - + return Mapper().toJSON(ident) } - + func buildPushRegistrationDict(deviceToken: String) -> [String:Any] { let deviceKitDevice = Device() - + let ident = PushRegistrationRequest() ident.AppBuildNumber = Int(string: Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion")! as! String) ident.AppBundleIdentifer = Bundle.main.bundleIdentifier @@ -630,13 +630,13 @@ public class HomeAssistantAPI { ident.APNSSandbox = ((Bundle.main.object(forInfoDictionaryKey: "IS_SANDBOXED") as! String) == "true") ident.HomeAssistantVersion = prefs.string(forKey: "version")! ident.HomeAssistantTimezone = prefs.string(forKey: "time_zone")! - + return Mapper().toJSON(ident) } - + func buildRemovalDict() -> [String:Any] { let deviceKitDevice = Device() - + let ident = IdentifyRequest() ident.AppBuildNumber = Int(string: Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion")! as! String) ident.AppBundleIdentifer = Bundle.main.bundleIdentifier @@ -653,10 +653,10 @@ public class HomeAssistantAPI { ident.PushID = pushID ident.PushSounds = listAllInstalledPushNotificationSounds() ident.PushToken = deviceToken - + return Mapper().toJSON(ident) } - + func identifyDevice() -> Promise { let queryUrl = baseAPIURL+"ios/identify" return Promise { fulfill, reject in @@ -672,7 +672,7 @@ public class HomeAssistantAPI { } } } - + func removeDevice() -> Promise { let queryUrl = baseAPIURL+"ios/identify" return Promise { fulfill, reject in @@ -688,7 +688,7 @@ public class HomeAssistantAPI { } } } - + func registerDeviceForPush(deviceToken: String) -> Promise { let queryUrl = "https://ios-push.home-assistant.io/registrations" return Promise { fulfill, reject in @@ -705,7 +705,7 @@ public class HomeAssistantAPI { } } } - + func setupPushActions() -> Promise> { let queryUrl = baseAPIURL+"ios/push" return Promise { fulfill, reject in @@ -750,7 +750,7 @@ public class HomeAssistantAPI { } } } - + @available(iOS 10, *) func setupUserNotificationPushActions() -> Promise> { let queryUrl = baseAPIURL+"ios/push" @@ -800,7 +800,7 @@ public class HomeAssistantAPI { } } } - + func setupPush() { UIApplication.shared.registerForRemoteNotifications() if #available(iOS 10, *) { @@ -812,7 +812,7 @@ public class HomeAssistantAPI { } } else { self.setupPushActions().then { categories -> Void in - let types:UIUserNotificationType = ([.alert, .badge, .sound]) + let types: UIUserNotificationType = ([.alert, .badge, .sound]) let settings = UIUserNotificationSettings(types: types, categories: categories) UIApplication.shared.registerUserNotificationSettings(settings) }.catch {error -> Void in @@ -821,11 +821,11 @@ public class HomeAssistantAPI { } } } - + func handlePushAction(identifier: String, userInfo: [AnyHashable : Any], userInput: String?) -> Promise { return Promise { fulfill, reject in let device = Device() - var eventData : [String:Any] = ["actionName": identifier, "sourceDevicePermanentID": DeviceUID.uid(), "sourceDeviceName": device.name] + var eventData: [String:Any] = ["actionName": identifier, "sourceDevicePermanentID": DeviceUID.uid(), "sourceDeviceName": device.name] if let dataDict = userInfo["homeassistant"] { eventData["action_data"] = dataDict } @@ -840,7 +840,7 @@ public class HomeAssistantAPI { } } } - + func getBeacons() -> Promise<[Beacon]> { let queryUrl = baseAPIURL+"ios/beacons" return Promise { fulfill, reject in @@ -856,7 +856,7 @@ public class HomeAssistantAPI { } } } - + func getImage(imageUrl: String) -> Promise { var url = imageUrl if url.hasPrefix("/local/") || url.hasPrefix("/api/") { @@ -879,31 +879,31 @@ public class HomeAssistantAPI { } } } - - var locationEnabled : Bool { + + var locationEnabled: Bool { // return PermissionScope().statusLocationAlways() == .authorized && self.loadedComponents.contains("device_tracker") return PermissionScope().statusLocationAlways() == .authorized } - - var notificationsEnabled : Bool { + + var notificationsEnabled: Bool { // return PermissionScope().statusNotifications() == .authorized && prefs.string(forKey: "pushID") != nil return prefs.string(forKey: "pushID") != nil // print("PermissionScope().statusNotifications()", PermissionScope().statusNotifications()) // return PermissionScope().statusNotifications() == .authorized } - - var iosComponentLoaded : Bool { + + var iosComponentLoaded: Bool { return self.loadedComponents.contains("ios") } - - var deviceTrackerComponentLoaded : Bool { + + var deviceTrackerComponentLoaded: Bool { return self.loadedComponents.contains("device_tracker") } - - var iosNotifyPlatformLoaded : Bool { + + var iosNotifyPlatformLoaded: Bool { return self.loadedComponents.contains("notify.ios") } - + var sseConnected: Bool { if let sse = self.eventSource { return sse.readyState == .open @@ -911,9 +911,9 @@ public class HomeAssistantAPI { return false } } - - var enabledPermissions : [String] { - var permissionsContainer : [String] = [] + + var enabledPermissions: [String] { + var permissionsContainer: [String] = [] for status in PermissionScope().permissionStatuses([NotificationsPermission().type, LocationAlwaysPermission().type]) { if status.1 == .authorized { permissionsContainer.append(status.0.prettyDescription.lowercased()) @@ -921,11 +921,11 @@ public class HomeAssistantAPI { } return permissionsContainer } - + func showMurmur(title: String) { show(whistle: Murmur(title: title), action: .show(2.0)) } - + func CleanBaseURL(baseUrl: URL) -> (hasValidScheme: Bool, cleanedURL: URL) { if (baseUrl.absoluteString.hasPrefix("http://") || baseUrl.absoluteString.hasPrefix("https://")) == false { return (false, baseUrl) @@ -939,7 +939,7 @@ public class HomeAssistantAPI { } return (true, urlComponents.url!) } - + func GetDiscoveryInfo(baseUrl: URL) -> Promise { let queryUrl = baseUrl.appendingPathComponent("/api/discovery_info") return Promise { fulfill, reject in @@ -955,36 +955,36 @@ public class HomeAssistantAPI { } } } - + } -class BonjourDelegate : NSObject, NetServiceBrowserDelegate, NetServiceDelegate { - +class BonjourDelegate: NSObject, NetServiceBrowserDelegate, NetServiceDelegate { + var resolving = [NetService]() - var resolvingDict = [String:NetService]() - + var resolvingDict = [String: NetService]() + // Browser methods - + func netServiceBrowser(_ netServiceBrowser: NetServiceBrowser, didFind netService: NetService, moreComing moreServicesComing: Bool) { NSLog("BonjourDelegate.Browser.didFindService") netService.delegate = self resolvingDict[netService.name] = netService netService.resolve(withTimeout: 0.0) } - + func netServiceDidResolveAddress(_ sender: NetService) { NSLog("BonjourDelegate.Browser.netServiceDidResolveAddress") let discoveryInfo = DiscoveryInfoFromDict(locationName: sender.name, netServiceDictionary: NetService.dictionary(fromTXTRecord: sender.txtRecordData()!)) NotificationCenter.default.post(name: NSNotification.Name(rawValue: "homeassistant.discovered"), object: nil, userInfo: discoveryInfo.toJSON()) } - + func netServiceBrowser(_ netServiceBrowser: NetServiceBrowser, didRemove netService: NetService, moreComing moreServicesComing: Bool) { NSLog("BonjourDelegate.Browser.didRemoveService") - let discoveryInfo : [NSObject:Any] = ["name" as NSObject: netService.name] + let discoveryInfo: [NSObject:Any] = ["name" as NSObject: netService.name] NotificationCenter.default.post(name: NSNotification.Name(rawValue: "homeassistant.undiscovered"), object: nil, userInfo: discoveryInfo) resolvingDict.removeValue(forKey: netService.name) } - + // func netServiceBrowser(netServiceBrowser: NetServiceBrowser, didFindDomain domainName: String, moreComing moreDomainsComing: Bool) { // NSLog("BonjourDelegate.Browser.netServiceBrowser.didFindDomain") // } @@ -1003,9 +1003,9 @@ class BonjourDelegate : NSObject, NetServiceBrowserDelegate, NetServiceDelegate // func netServiceWillPublish(sender: NetService) { // NSLog("BonjourDelegate.Browser.netServiceWillPublish:\(sender)"); // } - + private func DiscoveryInfoFromDict(locationName: String, netServiceDictionary: [String : Data]) -> DiscoveryInfoResponse { - var outputDict : [String:Any] = [:] + var outputDict: [String:Any] = [:] for (key, value) in netServiceDictionary { outputDict[key] = String(data: value, encoding: .utf8) if outputDict[key] as? String == "true" || outputDict[key] as? String == "false" { @@ -1015,9 +1015,9 @@ class BonjourDelegate : NSObject, NetServiceBrowserDelegate, NetServiceDelegate outputDict["location_name"] = locationName return DiscoveryInfoResponse(JSON: outputDict)! } - + // Publisher methods - + // func netService(sender: NetService, didNotPublish errorDict: [String : NSNumber]) { // NSLog("BonjourDelegate.Publisher.didNotPublish:\(sender)"); // } @@ -1039,20 +1039,20 @@ class BonjourDelegate : NSObject, NetServiceBrowserDelegate, NetServiceDelegate // func netService(sender: NetService, didAcceptConnectionWithInputStream inputStream: NSInputStream, outputStream stream: NSOutputStream) { // NSLog("BonjourDelegate.Publisher.netServiceDidAcceptConnection:\(sender)"); // } - + } class Bonjour { var nsb: NetServiceBrowser var nsp: NetService var nsdel: BonjourDelegate? - + init() { let device = Device() self.nsb = NetServiceBrowser() self.nsp = NetService(domain: "local", type: "_hass-ios._tcp.", name: device.name, port: 65535) } - + func buildPublishDict() -> [String: Data] { return [ "permanentID": DeviceUID.uid().data(using: .utf8)!, @@ -1061,28 +1061,28 @@ class Bonjour { "buildNumber": (Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as! String).data(using: .utf8)! ] } - + func startDiscovery() { self.nsdel = BonjourDelegate() nsb.delegate = nsdel nsb.searchForServices(ofType: "_home-assistant._tcp.", inDomain: "local.") } - + func stopDiscovery() { nsb.stop() } - + func startPublish() { // self.nsdel = BonjourDelegate() // nsp.delegate = nsdel nsp.setTXTRecord(NetService.data(fromTXTRecord: buildPublishDict())) nsp.publish() } - + func stopPublish() { nsp.stop() } - + } enum LocationUpdateTypes { diff --git a/HomeAssistant/Utilities/NSURL+QueryDictionary.swift b/HomeAssistant/Utilities/NSURL+QueryDictionary.swift index b43e7fa53..3b8e449e0 100644 --- a/HomeAssistant/Utilities/NSURL+QueryDictionary.swift +++ b/HomeAssistant/Utilities/NSURL+QueryDictionary.swift @@ -1,4 +1,3 @@ - // // NSURL+QueryDictionary.swift // HomeAssistant @@ -8,32 +7,31 @@ // import Foundation -extension URL -{ - var queryDictionary:[String: [String]]? { +extension URL { + var queryDictionary: [String: [String]]? { get { if let query = self.query { var dictionary = [String: [String]]() - + for keyValueString in query.components(separatedBy: "&") { var parts = keyValueString.components(separatedBy: "=") if parts.count < 2 { continue; } - + let key = parts[0].removingPercentEncoding! let value = parts[1].removingPercentEncoding! - + var values = dictionary[key] ?? [String]() values.append(value) dictionary[key] = values } - + return dictionary } - + return nil } } - + var queryItems: [String: String]? { var params = [String: String]() return URLComponents(url: self, resolvingAgainstBaseURL: false)? diff --git a/HomeAssistant/Utilities/OpenInChromeController.swift b/HomeAssistant/Utilities/OpenInChromeController.swift index 7bb9dccbf..6bc385591 100644 --- a/HomeAssistant/Utilities/OpenInChromeController.swift +++ b/HomeAssistant/Utilities/OpenInChromeController.swift @@ -41,13 +41,13 @@ private func encodeByAddingPercentEscapes(_ input: String?) -> String { open class OpenInChromeController { open static let sharedInstance = OpenInChromeController() - + open func isChromeInstalled() -> Bool { let simpleURL = URL(string: googleChromeHTTPScheme)! let callbackURL = URL(string: googleChromeCallbackScheme)! - return UIApplication.shared.canOpenURL(simpleURL) || UIApplication.shared.canOpenURL(callbackURL); + return UIApplication.shared.canOpenURL(simpleURL) || UIApplication.shared.canOpenURL(callbackURL) } - + open func openInChrome(_ url: URL, callbackURL: URL? = nil, createNewTab: Bool = false) -> Bool { let chromeSimpleURL = URL(string: googleChromeHTTPScheme)! let chromeCallbackURL = URL(string: googleChromeCallbackScheme)! @@ -82,6 +82,6 @@ open class OpenInChromeController { return UIApplication.shared.openURL(URL(string: chromeURLString)!) } } - return false; + return false } } diff --git a/HomeAssistant/Utilities/Utils.swift b/HomeAssistant/Utilities/Utils.swift index 08afb37de..42065b4e6 100644 --- a/HomeAssistant/Utilities/Utils.swift +++ b/HomeAssistant/Utilities/Utils.swift @@ -35,15 +35,15 @@ func getIconForIdentifier(_ iconIdentifier: String, iconWidth: Double, iconHeigh return theIcon!.image(with: CGSize(width: CGFloat(iconWidth), height: CGFloat(iconHeight))) } -func colorWithHexString(_ hexString: String, alpha:CGFloat? = 1.0) -> UIColor { - +func colorWithHexString(_ hexString: String, alpha: CGFloat? = 1.0) -> UIColor { + // Convert hex string to an integer let hexint = Int(intFromHexString(hexString)) let red = CGFloat((hexint & 0xff0000) >> 16) / 255.0 let green = CGFloat((hexint & 0xff00) >> 8) / 255.0 let blue = CGFloat((hexint & 0xff) >> 0) / 255.0 let alpha = alpha! - + // Create color object, specifying alpha as well let color = UIColor(red: red, green: green, blue: blue, alpha: alpha) return color @@ -64,12 +64,12 @@ func intFromHexString(_ hexStr: String) -> UInt32 { // Must reboot device after installing new push sounds (http://stackoverflow.com/questions/34998278/change-push-notification-sound-file-only-works-after-ios-reboot) func movePushNotificationSounds() -> Int { - + let fileManager: FileManager = FileManager() - + let libraryPath = try! fileManager.url(for: .libraryDirectory, in: FileManager.SearchPathDomainMask.userDomainMask, appropriateFor: nil, create: false) let librarySoundsPath = libraryPath.appendingPathComponent("Sounds") - + do { print("Creating sounds directory at", librarySoundsPath) try fileManager.createDirectory(at: librarySoundsPath, withIntermediateDirectories: true, attributes: nil) @@ -77,7 +77,7 @@ func movePushNotificationSounds() -> Int { print("Error creating /Library/Sounds directory", error) return 0 } - + let documentsPath = try! fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) let fileList = try! fileManager.contentsOfDirectory(at: documentsPath, includingPropertiesForKeys: nil, options: FileManager.DirectoryEnumerationOptions()) var movedFiles = 0 @@ -100,9 +100,9 @@ func movePushNotificationSounds() -> Int { } func getSoundList() -> [String] { - var result:[String] = [] + var result: [String] = [] let fileManager = FileManager.default - let enumerator:FileManager.DirectoryEnumerator = fileManager.enumerator(atPath: "/System/Library/Audio/UISounds/New")! + let enumerator: FileManager.DirectoryEnumerator = fileManager.enumerator(atPath: "/System/Library/Audio/UISounds/New")! for url in enumerator.allObjects { result.append(url as! String) } @@ -110,9 +110,9 @@ func getSoundList() -> [String] { } // copy sound file to /Library/Sounds directory, it will be auto detect and played when a push notification arrive -func copyFileToDirectory(_ fileName:String) { +func copyFileToDirectory(_ fileName: String) { let fileManager = FileManager.default - + let libraryDir = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.libraryDirectory, FileManager.SearchPathDomainMask.userDomainMask, true) let directoryPath = "\(libraryDir.first!)/Sounds" do { @@ -122,10 +122,10 @@ func copyFileToDirectory(_ fileName:String) { print("Error creating /Library/Sounds directory", error) return } - + let systemSoundPath = "/System/Library/Audio/UISounds/New/\(fileName)" let notificationSoundPath = "\(directoryPath)/\(fileName)" - + let fileExist = fileManager.fileExists(atPath: notificationSoundPath) if (fileExist) { try! fileManager.removeItem(atPath: notificationSoundPath) @@ -135,14 +135,14 @@ func copyFileToDirectory(_ fileName:String) { func listAllInstalledPushNotificationSounds() -> [String] { let fileManager: FileManager = FileManager() - + let libraryPath = try! fileManager.url(for: .libraryDirectory, in: FileManager.SearchPathDomainMask.userDomainMask, appropriateFor: nil, create: false) let librarySoundsPath = libraryPath.appendingPathComponent("Sounds") - + let librarySoundsContents = fileManager.enumerator(at: librarySoundsPath, includingPropertiesForKeys: nil, options: FileManager.DirectoryEnumerationOptions(), errorHandler: nil)! - + var allSounds = [String]() - + for obj in librarySoundsContents.allObjects { let file = obj as! URL allSounds.append(file.lastPathComponent) @@ -151,16 +151,16 @@ func listAllInstalledPushNotificationSounds() -> [String] { } func migrateUserDefaultsToAppGroups() { - + // User Defaults - Old let userDefaults = UserDefaults.standard - + // App Groups Default - New let groupDefaults = UserDefaults(suiteName: "group.io.robbie.homeassistant") - + // Key to track if we migrated let didMigrateToAppGroups = "DidMigrateToAppGroups" - + if let groupDefaults = groupDefaults { if !groupDefaults.bool(forKey: didMigrateToAppGroups) { for key in userDefaults.dictionaryRepresentation().keys { @@ -175,14 +175,14 @@ func migrateUserDefaultsToAppGroups() { } else { print("Unable to create NSUserDefaults with given app group") } - + } func logUserDefaults() { - + let userDefaults = UserDefaults.standard let groupDefaults = UserDefaults(suiteName: "group.io.robbie.homeassistant") - + if let groupDefaults = groupDefaults { for key in groupDefaults.dictionaryRepresentation().keys { print("groupDefaults \(key): \(groupDefaults.dictionaryRepresentation()[key])") @@ -190,7 +190,7 @@ func logUserDefaults() { } else { print("Unable to create NSUserDefaults with given app group") } - + for key in userDefaults.dictionaryRepresentation().keys { print("userDefaults \(key): \(userDefaults.dictionaryRepresentation()[key])") } @@ -218,27 +218,27 @@ func openURLInBrowser(url: String) { } func removeSpecialCharsFromString(text: String) -> String { - let okayChars : Set = + let okayChars: Set = Set("abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLKMNOPQRSTUVWXYZ1234567890".characters) return String(text.characters.filter {okayChars.contains($0) }) } -extension UIImage{ - func scaledToSize(_ size: CGSize) -> UIImage{ +extension UIImage { + func scaledToSize(_ size: CGSize) -> UIImage { UIGraphicsBeginImageContextWithOptions(size, false, 0.0) self.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height)) - let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()! + let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() return newImage } } extension String { - + subscript (i: Int) -> Character { return self[self.characters.index(self.startIndex, offsetBy: i)] } - + subscript (i: Int) -> String { return String(self[i] as Character) } diff --git a/HomeAssistant/Views/AboutViewController.swift b/HomeAssistant/Views/AboutViewController.swift index 85bc9f2fd..1a83d493e 100644 --- a/HomeAssistant/Views/AboutViewController.swift +++ b/HomeAssistant/Views/AboutViewController.swift @@ -12,12 +12,12 @@ import SafariServices import CPDAcknowledgements class AboutViewController: FormViewController { - + override func viewDidLoad() { super.viewDidLoad() - + self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(AboutViewController.closeAboutView(_:))) - + form +++ Section() { $0.header = HeaderFooterView(.nibFile(name: "HomeAssistantLogoView", bundle: nil)) @@ -33,7 +33,7 @@ class AboutViewController: FormViewController { +++ Section() <<< ButtonRow() { $0.title = "Website" - }.cellUpdate{ cell, row in + }.cellUpdate { cell, _ in cell.textLabel?.textAlignment = .left cell.accessoryType = .disclosureIndicator cell.editingAccessoryType = cell.accessoryType @@ -41,10 +41,10 @@ class AboutViewController: FormViewController { }.onCellSelection({ _ in openURLInBrowser(url: "https://home-assistant.io/") }) - + <<< ButtonRow() { $0.title = "Forums" - }.cellUpdate{ cell, row in + }.cellUpdate { cell, _ in cell.textLabel?.textAlignment = .left cell.accessoryType = .disclosureIndicator cell.editingAccessoryType = cell.accessoryType @@ -52,10 +52,10 @@ class AboutViewController: FormViewController { }.onCellSelection({ _ in openURLInBrowser(url: "https://community.home-assistant.io/") }) - + <<< ButtonRow() { $0.title = "Chat" - }.cellUpdate{ cell, row in + }.cellUpdate { cell, _ in cell.textLabel?.textAlignment = .left cell.accessoryType = .disclosureIndicator cell.editingAccessoryType = cell.accessoryType @@ -63,10 +63,10 @@ class AboutViewController: FormViewController { }.onCellSelection({ _ in openURLInBrowser(url: "https://gitter.im/home-assistant/home-assistant") }) - + <<< ButtonRow() { $0.title = "Documentation" - }.cellUpdate{ cell, row in + }.cellUpdate { cell, _ in cell.textLabel?.textAlignment = .left cell.accessoryType = .disclosureIndicator cell.editingAccessoryType = cell.accessoryType @@ -74,10 +74,10 @@ class AboutViewController: FormViewController { }.onCellSelection({ _ in openURLInBrowser(url: "https://home-assistant.io/ecosystem/ios/") }) - + <<< ButtonRow() { $0.title = "Home Assistant on Twitter" - }.cellUpdate{ cell, row in + }.cellUpdate { cell, _ in cell.textLabel?.textAlignment = .left cell.accessoryType = .disclosureIndicator cell.editingAccessoryType = cell.accessoryType @@ -85,10 +85,10 @@ class AboutViewController: FormViewController { }.onCellSelection({ _ in self.openInTwitterApp(username: "home_assistant") }) - + <<< ButtonRow() { $0.title = "Home Assistant on Facebook" - }.cellUpdate{ cell, row in + }.cellUpdate { cell, _ in cell.textLabel?.textAlignment = .left cell.accessoryType = .disclosureIndicator cell.editingAccessoryType = cell.accessoryType @@ -96,10 +96,10 @@ class AboutViewController: FormViewController { }.onCellSelection({ _ in self.openInFacebook(pageId: "292963007723872") }) - + <<< ButtonRow() { $0.title = "GitHub" - }.cellUpdate{ cell, row in + }.cellUpdate { cell, _ in cell.textLabel?.textAlignment = .left cell.accessoryType = .disclosureIndicator cell.editingAccessoryType = cell.accessoryType @@ -107,10 +107,10 @@ class AboutViewController: FormViewController { }.onCellSelection({ _ in openURLInBrowser(url: "https://github.com/home-assistant/home-assistant-iOS") }) - + <<< ButtonRow() { $0.title = "GitHub Issue Tracker" - }.cellUpdate{ cell, row in + }.cellUpdate { cell, _ in cell.textLabel?.textAlignment = .left cell.accessoryType = .disclosureIndicator cell.editingAccessoryType = cell.accessoryType @@ -118,15 +118,14 @@ class AboutViewController: FormViewController { }.onCellSelection({ _ in openURLInBrowser(url: "https://github.com/home-assistant/home-assistant-iOS/issues") }) - + } - + override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } - - + /* // MARK: - Navigation @@ -136,7 +135,7 @@ class AboutViewController: FormViewController { // Pass the selected object to the new view controller. } */ - + func generateAcknowledgements() -> CPDAcknowledgementsViewController { // let robbie = CPDContribution.init(name: "Robbie Trencheny", websiteAddress: "https://twitter.com/robbie", role: "Primary iOS developer") // robbie.avatarAddress = "https://s.gravatar.com/avatar/04178c46aa6f009adba24b3e7ac64f14" @@ -145,7 +144,7 @@ class AboutViewController: FormViewController { // let contributors = [robbie, paulus] return CPDAcknowledgementsViewController.init(style: nil, acknowledgements: nil, contributions: nil) } - + func openInTwitterApp(username: String) { /* Tweetbot app precedence */ if let tweetbotURL = URL(string: "tweetbot:///user_profile/"+username) { @@ -158,7 +157,7 @@ class AboutViewController: FormViewController { return } } - + /* Twitter app fallback */ if let twitterURL = URL(string: "twitter:///user?screen_name="+username) { if UIApplication.shared.canOpenURL(twitterURL) { @@ -170,7 +169,7 @@ class AboutViewController: FormViewController { return } } - + /* Safari fallback */ if let webURL = URL(string: "https://twitter.com/"+username) { if UIApplication.shared.canOpenURL(webURL) { @@ -183,7 +182,7 @@ class AboutViewController: FormViewController { } } } - + func openInFacebook(pageId: String) { if let facebookURL = URL(string: "fb://page/"+pageId) { if UIApplication.shared.canOpenURL(facebookURL) { @@ -196,18 +195,18 @@ class AboutViewController: FormViewController { } } } - + func closeAboutView(_ sender: UIBarButtonItem) { self.navigationController?.dismiss(animated: true, completion: nil) } } class HomeAssistantLogoView: UIView { - + required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } - + // override init(frame: CGRect) { // super.init(frame: frame) // let imageView = UIImageView(image: UIImage(named: "Logo")) diff --git a/HomeAssistant/Views/DevicesMapViewController.swift b/HomeAssistant/Views/DevicesMapViewController.swift index 77edbf005..286ac2bb9 100644 --- a/HomeAssistant/Views/DevicesMapViewController.swift +++ b/HomeAssistant/Views/DevicesMapViewController.swift @@ -27,48 +27,48 @@ class HACircle: MKCircle { class DevicesMapViewController: UIViewController, MKMapViewDelegate { var mapView: MKMapView! - + override func viewDidLoad() { super.viewDidLoad() self.title = "Devices & Zones" - + self.navigationController?.isToolbarHidden = false - + let items = ["Standard", "Hybrid", "Satellite"] let typeController = UISegmentedControl(items: items) typeController.selectedSegmentIndex = 0 typeController.addTarget(self, action: #selector(DevicesMapViewController.switchMapType(_:)), for: .valueChanged) - + let uploadIcon = getIconForIdentifier("mdi:upload", iconWidth: 30, iconHeight: 30, color: colorWithHexString("#44739E", alpha: 1)) - + self.navigationItem.leftBarButtonItem = UIBarButtonItem(image: uploadIcon, style: .plain, target: self, action: #selector(DevicesMapViewController.sendCurrentLocation(_:))) - + self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(DevicesMapViewController.closeMapView(_:))) - + // Do any additional setup after loading the view. mapView = MKMapView() - + mapView.mapType = .standard mapView.frame = view.frame mapView.delegate = self mapView.showsUserLocation = false mapView.showsPointsOfInterest = false view.addSubview(mapView) - + let locateMeButton = MKUserTrackingBarButtonItem(mapView: mapView) let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil) let segmentedControlButtonItem = UIBarButtonItem(customView: typeController) // let bookmarksButton = UIBarButtonItem(barButtonSystemItem: .Bookmarks, target: self, action: nil) - + self.setToolbarItems([locateMeButton, flexibleSpace, segmentedControlButtonItem, flexibleSpace], animated: true) - + for zone in realm.objects(Zone.self) { let circle = HACircle.init(center: zone.locationCoordinates(), radius: CLLocationDistance(zone.Radius)) circle.type = "zone" mapView.add(circle) } - + for device in realm.objects(DeviceTracker.self) { if device.Latitude.value == nil || device.Longitude.value == nil { continue @@ -76,7 +76,7 @@ class DevicesMapViewController: UIViewController, MKMapViewDelegate { let dropPin = DeviceAnnotation() dropPin.coordinate = device.locationCoordinates() dropPin.title = device.Name - var subtitlePieces : [String] = [] + var subtitlePieces: [String] = [] // if let changedTime = device.LastChanged { // subtitlePieces.append("Last seen: "+changedTime.toRelativeString(abbreviated: true, maxUnits: 1)!+" ago") // } @@ -86,30 +86,30 @@ class DevicesMapViewController: UIViewController, MKMapViewDelegate { dropPin.subtitle = subtitlePieces.joined(separator: " / ") dropPin.device = device mapView.addAnnotation(dropPin) - + if let radius = device.GPSAccuracy.value { let circle = HACircle.init(center: device.locationCoordinates(), radius: radius) circle.type = "device" mapView.add(circle) } - + } - - var zoomRect:MKMapRect = MKMapRectNull + + var zoomRect: MKMapRect = MKMapRectNull for index in 0.. MKAnnotationView? { if let annotation = annotation as? DeviceAnnotation { let annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: annotation.device?.ID) @@ -145,7 +145,7 @@ class DevicesMapViewController: UIViewController, MKMapViewDelegate { return nil } } - + func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer { if let overlay = overlay as? HACircle { let circle = MKCircleRenderer(overlay: overlay) @@ -164,13 +164,13 @@ class DevicesMapViewController: UIViewController, MKMapViewDelegate { return MKOverlayRenderer(overlay: overlay) } } - + func closeMapView(_ sender: UIBarButtonItem) { self.navigationController?.dismiss(animated: true, completion: nil) } - + func sendCurrentLocation(_ sender: UIBarButtonItem) { - HomeAssistantAPI.sharedInstance.sendOneshotLocation().then { success -> Void in + HomeAssistantAPI.sharedInstance.sendOneshotLocation().then { _ -> Void in let alert = UIAlertController(title: "Location updated", message: "Successfully sent a one shot location to the server", preferredStyle: UIAlertControllerStyle.alert) alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil)) self.present(alert, animated: true, completion: nil) diff --git a/HomeAssistant/Views/EntityAttributesViewController.swift b/HomeAssistant/Views/EntityAttributesViewController.swift index 2ffd75f70..3ede9eaa3 100644 --- a/HomeAssistant/Views/EntityAttributesViewController.swift +++ b/HomeAssistant/Views/EntityAttributesViewController.swift @@ -14,36 +14,36 @@ import RealmSwift class EntityAttributesViewController: FormViewController { var entityID: String = "" - + override func viewDidLoad() { super.viewDidLoad() let entity = realm.object(ofType: Entity.self, forPrimaryKey: entityID as AnyObject) - + self.title = (entity?.FriendlyName != nil) ? entity?.Name : "Attributes" - + if let picture = entity!.Picture { form +++ Section() - <<< TextAreaRow("entity_picture"){ + <<< TextAreaRow("entity_picture") { $0.disabled = true $0.cell.textView.isScrollEnabled = false $0.cell.textView.backgroundColor = UIColor.clear $0.cell.backgroundColor = UIColor.clear - }.cellUpdate { cell, row in + }.cellUpdate { cell, _ in let _ = HomeAssistantAPI.sharedInstance.getImage(imageUrl: picture).then { image -> Void in let attachment = NSTextAttachment() attachment.image = image attachment.bounds = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height) let attString = NSAttributedString(attachment: attachment) let result = NSMutableAttributedString(attributedString: attString) - + let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.alignment = .center - - let attrs:[String:AnyObject] = [NSParagraphStyleAttributeName: paragraphStyle] + + let attrs: [String:AnyObject] = [NSParagraphStyleAttributeName: paragraphStyle] let range = NSMakeRange(0, result.length) result.addAttributes(attrs, range: range) - + cell.textView.textStorage.setAttributedString(result) cell.height = { attachment.bounds.height + 20 } self.tableView?.beginUpdates() @@ -51,18 +51,18 @@ class EntityAttributesViewController: FormViewController { } } } - + form +++ Section(header: "Attributes", footer: "") - + var attributes = entity!.Attributes - + attributes["state"] = entity?.State for attribute in attributes { let prettyLabel = attribute.0.replacingOccurrences(of: "_", with: " ").capitalized switch attribute.0 { case "fan": if let thermostat = entity as? Thermostat { - form.last! <<< SwitchRow(attribute.0){ + form.last! <<< SwitchRow(attribute.0) { $0.title = prettyLabel $0.value = thermostat.Fan }.onChange { row -> Void in @@ -76,7 +76,7 @@ class EntityAttributesViewController: FormViewController { break case "away_mode": if let thermostat = entity as? Thermostat { - form.last! <<< SwitchRow(attribute.0){ + form.last! <<< SwitchRow(attribute.0) { $0.title = prettyLabel $0.value = thermostat.AwayMode }.onChange { row -> Void in @@ -90,7 +90,7 @@ class EntityAttributesViewController: FormViewController { break case "temperature": if let thermostat = entity as? Thermostat { - form.last! <<< SliderRow(attribute.0){ + form.last! <<< SliderRow(attribute.0) { $0.title = prettyLabel $0.value = Float(thermostat.Temperature!) $0.maximumValue = 120.0 @@ -102,7 +102,7 @@ class EntityAttributesViewController: FormViewController { break case "media_duration": if let mediaPlayer = entity as? MediaPlayer { - form.last! <<< TextRow(attribute.0){ + form.last! <<< TextRow(attribute.0) { $0.title = prettyLabel $0.value = mediaPlayer.humanReadableMediaDuration() $0.disabled = true @@ -111,7 +111,7 @@ class EntityAttributesViewController: FormViewController { break case "is_volume_muted": if let mediaPlayer = entity as? MediaPlayer { - form.last! <<< SwitchRow(attribute.0){ + form.last! <<< SwitchRow(attribute.0) { $0.title = "Mute" $0.value = mediaPlayer.IsVolumeMuted.value }.onChange { row -> Void in @@ -126,7 +126,7 @@ class EntityAttributesViewController: FormViewController { case "volume_level": if let mediaPlayer = entity as? MediaPlayer { let volume = Float(attribute.1 as! NSNumber)*100 - form.last! <<< SliderRow(attribute.0){ + form.last! <<< SliderRow(attribute.0) { $0.title = prettyLabel $0.value = volume $0.maximumValue = 100 @@ -155,15 +155,14 @@ class EntityAttributesViewController: FormViewController { fallthrough } default: - form.last! <<< TextRow(attribute.0){ + form.last! <<< TextRow(attribute.0) { $0.title = prettyLabel $0.value = String(describing: attribute.1).capitalized $0.disabled = true } } } - - + // Do any additional setup after loading the view. NotificationCenter.default.addObserver(self, selector: #selector(EntityAttributesViewController.StateChangedSSEEvent(_:)), name:NSNotification.Name(rawValue: "sse.state_changed"), object: nil) } @@ -172,15 +171,14 @@ class EntityAttributesViewController: FormViewController { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } - - func StateChangedSSEEvent(_ notification: NSNotification){ + func StateChangedSSEEvent(_ notification: NSNotification) { if let userInfo = (notification as NSNotification).userInfo { if let event = Mapper().map(JSON: userInfo as! [String : Any]) { if event.EntityID != entityID { return } let entity = realm.object(ofType: Entity.self, forPrimaryKey: entityID as AnyObject) if let newState = event.NewState { - var updateDict : [String:Any] = [:] + var updateDict: [String:Any] = [:] newState.Attributes["state"] = entity?.State for (key, value) in newState.Attributes { switch key { diff --git a/HomeAssistant/Views/EurekaLocationRow.swift b/HomeAssistant/Views/EurekaLocationRow.swift index cf055799a..34044dabe 100644 --- a/HomeAssistant/Views/EurekaLocationRow.swift +++ b/HomeAssistant/Views/EurekaLocationRow.swift @@ -11,13 +11,13 @@ import UIKit import Eureka import MapKit -//MARK: LocationRow +// MARK: LocationRow -public final class LocationRow : SelectorRow, MapViewController>, RowType { +public final class LocationRow: SelectorRow, MapViewController>, RowType { public required init(tag: String?) { super.init(tag: tag) - presentationMode = .show(controllerProvider: ControllerProvider.callback { return MapViewController(){ _ in } }, onDismiss: { vc in _ = vc.navigationController?.popViewController(animated: true) }) - + presentationMode = .show(controllerProvider: ControllerProvider.callback { return MapViewController() { _ in } }, onDismiss: { vc in _ = vc.navigationController?.popViewController(animated: true) }) + displayValueFor = { guard let location = $0 else { return "" } let fmt = NumberFormatter() @@ -30,38 +30,38 @@ public final class LocationRow : SelectorRow, MapVi } } -public class MapViewController : UIViewController, TypedRowControllerType, MKMapViewDelegate { - +public class MapViewController: UIViewController, TypedRowControllerType, MKMapViewDelegate { + public var row: RowOf! /// A closure to be called when the controller disappears. - public var onDismissCallback: ((UIViewController) -> ())? - - lazy var mapView : MKMapView = { [unowned self] in + public var onDismissCallback: ((UIViewController) -> Void)? + + lazy var mapView: MKMapView = { [unowned self] in let v = MKMapView(frame: self.view.bounds) v.autoresizingMask = UIViewAutoresizing.flexibleWidth.union(UIViewAutoresizing.flexibleHeight) return v }() - + required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } - + public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { super.init(nibName: nil, bundle: nil) } - - convenience public init(_ callback: ((UIViewController) -> ())?){ + + convenience public init(_ callback: ((UIViewController) -> Void)?) { self.init(nibName: nil, bundle: nil) onDismissCallback = callback } - + public override func viewDidLoad() { super.viewDidLoad() view.addSubview(mapView) - + mapView.delegate = self mapView.showsUserLocation = true - + if let value = row.value { let dropPin = MKPointAnnotation() dropPin.coordinate = value.coordinate @@ -75,7 +75,7 @@ public class MapViewController : UIViewController, TypedRowControllerType, MKMap mapView.add(circle) } } - + let fmt = NumberFormatter() fmt.maximumFractionDigits = 4 fmt.minimumFractionDigits = 4 @@ -83,7 +83,7 @@ public class MapViewController : UIViewController, TypedRowControllerType, MKMap let longitude = fmt.string(from: NSNumber(value: mapView.centerCoordinate.longitude))! title = "\(latitude), \(longitude)" } - + public func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer { if let overlay = overlay as? HACircle { let circle = MKCircleRenderer(overlay: overlay) diff --git a/HomeAssistant/Views/GroupViewController.swift b/HomeAssistant/Views/GroupViewController.swift index 37204a47c..ec64710c0 100644 --- a/HomeAssistant/Views/GroupViewController.swift +++ b/HomeAssistant/Views/GroupViewController.swift @@ -14,23 +14,23 @@ import ObjectMapper import RealmSwift class GroupViewController: FormViewController { - - var groupsMap = [String:[String]]() - + + var groupsMap = [String: [String]]() + var GroupID: String = "" var Order: Int? - - var entities = [String:Entity]() - - var sendingEntity : Entity? - + + var entities = [String: Entity]() + + var sendingEntity: Entity? + override func viewDidLoad() { - + super.viewDidLoad() - + if GroupID != "" { let group = realm.object(ofType: Group.self, forPrimaryKey: GroupID as AnyObject) - + self.form +++ Section() for entity in group!.Entities { @@ -54,9 +54,9 @@ class GroupViewController: FormViewController { case "script", "scene": self.form.last! <<< ButtonRow(entity.ID) { $0.title = entity.Name - }.onCellSelection { cell, row -> Void in + }.onCellSelection { _, _ -> Void in let _ = HomeAssistantAPI.sharedInstance.turnOn(entityId: entity.ID) - }.cellUpdate { cell, row in + }.cellUpdate { cell, _ in cell.imageView?.image = entity.EntityIcon if let picture = entity.DownloadedPicture { cell.imageView?.image = picture.scaledToSize(CGSize(width: 30, height: 30)) @@ -69,12 +69,12 @@ class GroupViewController: FormViewController { if url.scheme == "http" || url.scheme == "https" { $0.presentationMode = .presentModally(controllerProvider: ControllerProvider.callback { return SFSafariViewController(url: url, entersReaderIfAvailable: false) }, onDismiss: { vc in let _ = vc.navigationController?.popViewController(animated: true) }) } - }.cellUpdate { cell, row in + }.cellUpdate { cell, _ in cell.imageView?.image = entity.EntityIcon if let picture = entity.DownloadedPicture { cell.imageView?.image = picture.scaledToSize(CGSize(width: 30, height: 30)) } - }.onCellSelection { cell, row -> Void in + }.onCellSelection { _, _ -> Void in if url.scheme != "http" && url.scheme != "https" { UIApplication.shared.openURL(url as URL) } @@ -91,7 +91,7 @@ class GroupViewController: FormViewController { }, onDismiss: { vc in let _ = vc.navigationController?.popViewController(animated: true) }) - }.cellUpdate { cell, row in + }.cellUpdate { cell, _ in cell.detailTextLabel?.text = entity.State.capitalized if let uom = entity.UnitOfMeasurement { cell.detailTextLabel?.text = (entity.State.capitalized + " " + uom) @@ -107,7 +107,7 @@ class GroupViewController: FormViewController { self.form.last! <<< LocationRow(entity.ID) { $0.title = entity.Name $0.value = dtracker.location() - }.cellUpdate { cell, row in + }.cellUpdate { cell, _ in cell.detailTextLabel?.text = entity.CleanedState cell.imageView?.image = entity.EntityIcon if let picture = entity.DownloadedPicture { @@ -123,7 +123,7 @@ class GroupViewController: FormViewController { attributesView.entityID = entity.ID return attributesView }, onDismiss: { vc in let _ = vc.navigationController?.popViewController(animated: true) }) - }.cellUpdate { cell, row in + }.cellUpdate { cell, _ in cell.detailTextLabel?.text = entity.CleanedState if let uom = entity.UnitOfMeasurement { cell.detailTextLabel?.text = (entity.State + " " + uom).replacingOccurrences(of: "_", with: " ").capitalized @@ -143,7 +143,7 @@ class GroupViewController: FormViewController { attributesView.entityID = entity.ID return attributesView }, onDismiss: { vc in let _ = vc.navigationController?.popViewController(animated: true) }) - }.cellUpdate { cell, row in + }.cellUpdate { cell, _ in cell.detailTextLabel?.text = entity.CleanedState if let uom = entity.UnitOfMeasurement { cell.detailTextLabel?.text = (entity.State + " " + uom).replacingOccurrences(of: "_", with: " ").capitalized @@ -173,7 +173,7 @@ class GroupViewController: FormViewController { $0.value = (entity.State == "locked") ? true : false }.onChange { row -> Void in let _ = HomeAssistantAPI.sharedInstance.CallService(domain: "lock", service: ((row.value == true) ? "lock" : "unlock"), serviceData: ["entity_id": entity.ID as AnyObject]) - }.cellUpdate { cell, row in + }.cellUpdate { cell, _ in cell.imageView?.image = entity.EntityIcon if let picture = entity.DownloadedPicture { cell.imageView?.image = picture.scaledToSize(CGSize(width: 30, height: 30)) @@ -185,14 +185,14 @@ class GroupViewController: FormViewController { $0.value = (entity.State == "open") ? true : false }.onChange { row -> Void in let _ = HomeAssistantAPI.sharedInstance.CallService(domain: "garage_door", service: ((row.value == true) ? "open" : "close"), serviceData: ["entity_id": entity.ID as AnyObject]) - }.cellUpdate { cell, row in + }.cellUpdate { cell, _ in cell.imageView?.image = entity.EntityIcon if let picture = entity.DownloadedPicture { cell.imageView?.image = picture.scaledToSize(CGSize(width: 30, height: 30)) } } case "input_slider": - self.form.last! <<< SliderRow(entity.ID){ + self.form.last! <<< SliderRow(entity.ID) { $0.title = entity.Name $0.value = Float(entity.State) if let slider = entity as? InputSlider { @@ -206,16 +206,16 @@ class GroupViewController: FormViewController { $0.steps = UInt(steps) } } - + }.onChange { row -> Void in if let slider = entity as? InputSlider { slider.SelectValue(row.value!) } - }.cellUpdate { cell, row in + }.cellUpdate { _, row in // if let uom = entity.UnitOfMeasurement { // cell.detailTextLabel?.text = (entity.State.capitalized + " " + uom) // } - row.displayValueFor = { (pos: Float?) in + row.displayValueFor = { (_) in if let uom = entity.UnitOfMeasurement { return (entity.State.capitalized + " " + uom) } else { @@ -228,28 +228,28 @@ class GroupViewController: FormViewController { } } } - + NotificationCenter.default.addObserver(self, selector: #selector(GroupViewController.StateChangedSSEEvent(_:)), name:NSNotification.Name(rawValue: "sse.state_changed"), object: nil) } - + override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } - - func StateChangedSSEEvent(_ notification: NSNotification){ + + func StateChangedSSEEvent(_ notification: NSNotification) { if let userInfo = (notification as NSNotification).userInfo { if let event = Mapper().map(JSON: userInfo as! [String : Any]) { if let newState = event.NewState { if newState.Domain == "lock" || newState.Domain == "garage_door" { - if let row : SwitchRow = self.form.rowBy(tag: newState.ID) { + if let row: SwitchRow = self.form.rowBy(tag: newState.ID) { row.value = (newState.State == "on") ? true : false row.cell.imageView?.image = newState.EntityIcon row.updateCell() row.reload() } } else { - if let row : ButtonRow = self.form.rowBy(tag: newState.ID) { + if let row: ButtonRow = self.form.rowBy(tag: newState.ID) { row.value = newState.State if let uom = newState.UnitOfMeasurement { row.value = newState.State + " " + uom @@ -263,7 +263,7 @@ class GroupViewController: FormViewController { } } } - + func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) { // Get the new view controller using segue.destinationViewController. // Pass the selected object to the new view controller. @@ -272,6 +272,5 @@ class GroupViewController: FormViewController { entityAttributesViewController.entityID = sendingEntity!.ID } } - - + } diff --git a/HomeAssistant/Views/RootTabBarViewController.swift b/HomeAssistant/Views/RootTabBarViewController.swift index 13b387e43..04d710b04 100644 --- a/HomeAssistant/Views/RootTabBarViewController.swift +++ b/HomeAssistant/Views/RootTabBarViewController.swift @@ -20,22 +20,22 @@ class RootTabBarViewController: UITabBarController, UITabBarControllerDelegate { // Do any additional setup after loading the view. NotificationCenter.default.addObserver(self, selector: #selector(RootTabBarViewController.StateChangedSSEEvent(_:)), name:NSNotification.Name(rawValue: "sse.state_changed"), object: nil) } - + override func viewWillAppear(_ animated: Bool) { let hud = MBProgressHUD.showAdded(to: self.view, animated: true) self.delegate = self - + let tabBarIconColor = colorWithHexString("#44739E", alpha: 1) - - var tabViewControllers : [UIViewController] = [] - + + var tabViewControllers: [UIViewController] = [] + let firstGroupView = GroupViewController() firstGroupView.title = "Loading..." - + self.viewControllers = [firstGroupView] - + if HomeAssistantAPI.sharedInstance.baseAPIURL == "" { DispatchQueue.main.async(execute: { let settingsView = SettingsViewController() @@ -46,7 +46,7 @@ class RootTabBarViewController: UITabBarController, UITabBarControllerDelegate { self.present(navController, animated: true, completion: nil) }) } - + let allGroups = realm.objects(Group.self).filter { var shouldReturn = true // if prefs.bool(forKey: "allowAllGroups") == false { @@ -87,58 +87,58 @@ class RootTabBarViewController: UITabBarController, UITabBarControllerDelegate { groupView.tabBarItem.title = groupName let icon = group.Entities.first!.EntityIcon(width: 30, height: 30, color: tabBarIconColor) groupView.tabBarItem = UITabBarItem(title: groupName, image: icon, tag: index) - + if group.Order.value == nil { // Save the index now since it should be first time running try! realm.write { group.Order.value = index } } - + if HomeAssistantAPI.sharedInstance.locationEnabled { - var rightBarItems : [UIBarButtonItem] = [] - + var rightBarItems: [UIBarButtonItem] = [] + let uploadIcon = getIconForIdentifier("mdi:upload", iconWidth: 30, iconHeight: 30, color: tabBarIconColor) - + rightBarItems.append(UIBarButtonItem(image: uploadIcon, style: .plain, target: self, action: #selector(RootTabBarViewController.sendCurrentLocation(_:)))) - + let mapIcon = getIconForIdentifier("mdi:map", iconWidth: 30, iconHeight: 30, color: tabBarIconColor) - + rightBarItems.append(UIBarButtonItem(image: mapIcon, style: .plain, target: self, action: #selector(RootTabBarViewController.openMapView(_:)))) - + groupView.navigationItem.setRightBarButtonItems(rightBarItems, animated: true) } - + let navController = UINavigationController(rootViewController: groupView) - + tabViewControllers.append(navController) } let settingsIcon = getIconForIdentifier("mdi:settings", iconWidth: 30, iconHeight: 30, color: tabBarIconColor) - + let settingsView = SettingsViewController() settingsView.title = "Settings" settingsView.tabBarItem = UITabBarItem(title: "Settings", image: settingsIcon, tag: 1) settingsView.hidesBottomBarWhenPushed = true - + tabViewControllers.append(UINavigationController(rootViewController: settingsView)) - + self.viewControllers = tabViewControllers - + tabViewControllers.removeLast() - + self.customizableViewControllers = tabViewControllers - + hud.hide(animated: true) } - + func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool { - return true; + return true } - + func tabBarController(_ tabBarController: UITabBarController, willEndCustomizing viewControllers: [UIViewController], changed: Bool) { - + } - + func tabBarController(_ tabBarController: UITabBarController, didEndCustomizing viewControllers: [UIViewController], changed: Bool) { if (changed) { for (index, view) in viewControllers.enumerated() { @@ -159,8 +159,8 @@ class RootTabBarViewController: UITabBarController, UITabBarControllerDelegate { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } - - func StateChangedSSEEvent(_ notification: Notification){ + + func StateChangedSSEEvent(_ notification: Notification) { if let userInfo = (notification as NSNotification).userInfo { if let jsonObj = userInfo["jsonObject"] as? [String: Any] { if let event = Mapper().map(JSON: jsonObj) { @@ -178,13 +178,13 @@ class RootTabBarViewController: UITabBarController, UITabBarControllerDelegate { func openMapView(_ sender: UIButton) { let devicesMapView = DevicesMapViewController() - + let navController = UINavigationController(rootViewController: devicesMapView) self.present(navController, animated: true, completion: nil) } - + func sendCurrentLocation(_ sender: UIButton) { - HomeAssistantAPI.sharedInstance.sendOneshotLocation().then { success -> Void in + HomeAssistantAPI.sharedInstance.sendOneshotLocation().then { _ -> Void in let alert = UIAlertController(title: "Location updated", message: "Successfully sent a one shot location to the server", preferredStyle: UIAlertControllerStyle.alert) alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil)) self.present(alert, animated: true, completion: nil) @@ -195,7 +195,7 @@ class RootTabBarViewController: UITabBarController, UITabBarControllerDelegate { self.present(alert, animated: true, completion: nil) } } - + /* // MARK: - Navigation diff --git a/HomeAssistant/Views/SettingsDetailViewController.swift b/HomeAssistant/Views/SettingsDetailViewController.swift index 59c528b2b..4f7584d56 100644 --- a/HomeAssistant/Views/SettingsDetailViewController.swift +++ b/HomeAssistant/Views/SettingsDetailViewController.swift @@ -15,13 +15,13 @@ import Crashlytics class SettingsDetailViewController: FormViewController { let prefs = UserDefaults(suiteName: "group.io.robbie.homeassistant")! - + var detailGroup: String = "display" - + override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. - + switch detailGroup { case "display": self.title = "Display Settings" @@ -51,7 +51,7 @@ class SettingsDetailViewController: FormViewController { $0.title = "Location" $0.value = zone.location() } - <<< LabelRow(){ + <<< LabelRow() { $0.title = "Radius" $0.value = "\(Int(zone.Radius)) m" } @@ -81,32 +81,32 @@ class SettingsDetailViewController: FormViewController { } $0.disabled = true $0.textAreaHeight = TextAreaHeight.dynamic(initialTextViewHeight: 40) - }.onCellSelection{ cell, row in + }.onCellSelection { _, row in let activityViewController = UIActivityViewController(activityItems: [row.value! as String], applicationActivities: nil) self.present(activityViewController, animated: true, completion: {}) } - + +++ Section(header: "", footer: "Updating push settings will request the latest push actions and categories from Home Assistant.") <<< ButtonRow() { $0.title = "Update push settings" - }.onCellSelection {_,_ in + }.onCellSelection {_, _ in HomeAssistantAPI.sharedInstance.setupPush() let alert = UIAlertController(title: "Settings Import", message: "Push settings imported from Home Assistant.", preferredStyle: UIAlertControllerStyle.alert) alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil)) self.present(alert, animated: true, completion: nil) } - + +++ Section(header: "", footer: "Custom push notification sounds can be added via iTunes.") <<< ButtonRow() { $0.title = "Import sounds from iTunes" - }.onCellSelection {_,_ in + }.onCellSelection {_, _ in let moved = movePushNotificationSounds() let message = (moved > 0) ? "\(moved) sounds were imported. Please restart your phone to complete the import." : "0 sounds were imported." let alert = UIAlertController(title: "Sounds Import", message: message, preferredStyle: UIAlertControllerStyle.alert) alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil)) self.present(alert, animated: true, completion: nil) } - + // <<< ButtonRow() { // $0.title = "Import system sounds" // }.onCellSelection {_,_ in diff --git a/HomeAssistant/Views/SettingsViewController.swift b/HomeAssistant/Views/SettingsViewController.swift index 67fd9618c..76a064aee 100644 --- a/HomeAssistant/Views/SettingsViewController.swift +++ b/HomeAssistant/Views/SettingsViewController.swift @@ -17,72 +17,72 @@ import Alamofire class SettingsViewController: FormViewController { let prefs = UserDefaults(suiteName: "group.io.robbie.homeassistant")! - + var showErrorConnectingMessage = false - - var baseURL : URL? = nil - var password : String? = nil + + var baseURL: URL? = nil + var password: String? = nil var configured: Bool = false - var connectStep : Int = 0 // 0 = pre-configuration, 1 = hostname entry, 2 = password entry + var connectStep: Int = 0 // 0 = pre-configuration, 1 = hostname entry, 2 = password entry let discovery = Bonjour() - + override func viewWillDisappear(_ animated: Bool) { NSLog("Stopping Home Assistant discovery") self.discovery.stopDiscovery() self.discovery.stopPublish() } - + override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. - + let aboutButton = UIBarButtonItem(title: "About", style: .plain, target: self, action: #selector(SettingsViewController.openAbout(_:))) - + self.navigationItem.setRightBarButton(aboutButton, animated: true) - + if let baseURL = prefs.string(forKey: "baseURL") { self.baseURL = URL(string: baseURL)! } - + if let apiPass = prefs.string(forKey: "apiPassword") { self.password = apiPass } - + self.configured = (self.baseURL != nil && self.password != nil) - + checkForEmail() - + if showErrorConnectingMessage { let alert = UIAlertController(title: "Connection error", message: "There was an error connecting to Home Assistant. Please confirm the settings are correct and save to attempt to reconnect.", preferredStyle: UIAlertControllerStyle.alert) alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil)) self.present(alert, animated: true, completion: nil) } - + if self.configured == false { connectStep = 1 - let queue = DispatchQueue(label: "io.robbie.homeassistant", attributes: []); + let queue = DispatchQueue(label: "io.robbie.homeassistant", attributes: []) queue.async { () -> Void in NSLog("Attempting to discover Home Assistant instances, also publishing app to Bonjour/mDNS to hopefully have HA load the iOS/ZeroConf components.") self.discovery.stopDiscovery() self.discovery.stopPublish() - + self.discovery.startDiscovery() self.discovery.startPublish() } - + NotificationCenter.default.addObserver(self, selector: #selector(SettingsViewController.HomeAssistantDiscovered(_:)), name:NSNotification.Name(rawValue: "homeassistant.discovered"), object: nil) - + NotificationCenter.default.addObserver(self, selector: #selector(SettingsViewController.HomeAssistantUndiscovered(_:)), name:NSNotification.Name(rawValue: "homeassistant.undiscovered"), object: nil) } - + NotificationCenter.default.addObserver(self, selector: #selector(SettingsViewController.SSEConnectionChange(_:)), name:NSNotification.Name(rawValue: "sse.opened"), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(SettingsViewController.SSEConnectionChange(_:)), name:NSNotification.Name(rawValue: "sse.error"), object: nil) - + NotificationCenter.default.addObserver(self, selector: #selector(SettingsViewController.Connected(_:)), name:NSNotification.Name(rawValue: "connected"), object: nil) - + form - +++ Section(header: "Discovered Home Assistants", footer: ""){ + +++ Section(header: "Discovered Home Assistants", footer: "") { $0.tag = "discoveredInstances" $0.hidden = true } @@ -117,7 +117,7 @@ class SettingsViewController: FormViewController { } } } - + <<< PasswordRow("apiPassword") { $0.title = "Password" $0.value = self.password @@ -127,7 +127,7 @@ class SettingsViewController: FormViewController { }.onChange { row in self.password = row.value } - + <<< ButtonRow("connect") { $0.title = "Connect" $0.hidden = Condition(booleanLiteral: self.configured) @@ -142,7 +142,7 @@ class SettingsViewController: FormViewController { apiPasswordRow.value = "" apiPasswordRow.hidden = Condition(booleanLiteral: !discoveryInfo.RequiresPassword) apiPasswordRow.evaluateHidden() - let discoverySection : Section = self.form.sectionBy(tag: "discoveredInstances")! + let discoverySection: Section = self.form.sectionBy(tag: "discoveredInstances")! discoverySection.hidden = true discoverySection.evaluateHidden() self.connectStep = 2 @@ -205,7 +205,7 @@ class SettingsViewController: FormViewController { } } - +++ Section(header: "Status", footer: ""){ + +++ Section(header: "Status", footer: "") { $0.tag = "status" $0.hidden = Condition(booleanLiteral: !self.configured) } @@ -241,7 +241,7 @@ class SettingsViewController: FormViewController { $0.value = HomeAssistantAPI.sharedInstance.iosNotifyPlatformLoaded ? "✔️" : "✖️" $0.hidden = Condition(booleanLiteral: HomeAssistantAPI.sharedInstance.notificationsEnabled == false) } - + +++ Section(header: "", footer: "Device ID is the identifier used when sending location updates to Home Assistant, as well as the target to send push notifications to.") <<< TextRow("deviceId") { $0.title = "Device ID" @@ -251,13 +251,13 @@ class SettingsViewController: FormViewController { $0.value = removeSpecialCharsFromString(text: UIDevice.current.name).replacingOccurrences(of: " ", with: "_").lowercased() } $0.cell.textField.autocapitalizationType = .none - }.cellUpdate { cell, row in + }.cellUpdate { _, row in if row.isHighlighted == false { self.prefs.setValue(row.value, forKey: "deviceId") self.prefs.synchronize() } } - +++ Section(){ + +++ Section() { $0.tag = "details" $0.hidden = Condition(booleanLiteral: !self.configured) } @@ -271,13 +271,13 @@ class SettingsViewController: FormViewController { // let _ = vc.navigationController?.popViewController(animated: true) // }) // } - - <<< ButtonRow("enableLocation"){ + + <<< ButtonRow("enableLocation") { $0.title = "Enable location tracking" $0.hidden = Condition(booleanLiteral: HomeAssistantAPI.sharedInstance.locationEnabled) - }.onCellSelection { cell, row in + }.onCellSelection { _, row in let pscope = PermissionScope() - + pscope.addPermission(LocationAlwaysPermission(), message: "We use this to inform\r\nHome Assistant of your device location and state.") pscope.show({finished, results in @@ -299,7 +299,7 @@ class SettingsViewController: FormViewController { print("Permissions finished, resetting API!") }) } - + <<< ButtonRow("locationSettings") { $0.title = "Location Settings" $0.hidden = Condition(booleanLiteral: !HomeAssistantAPI.sharedInstance.locationEnabled) @@ -311,13 +311,13 @@ class SettingsViewController: FormViewController { let _ = vc.navigationController?.popViewController(animated: true) }) } - - <<< ButtonRow("enableNotifications"){ + + <<< ButtonRow("enableNotifications") { $0.title = "Enable notifications" $0.hidden = Condition(booleanLiteral: HomeAssistantAPI.sharedInstance.notificationsEnabled) - }.onCellSelection { cell, row in + }.onCellSelection { _, row in let pscope = PermissionScope() - + pscope.addPermission(NotificationsPermission(), message: "We use this to let you\r\nsend notifications to your device.") pscope.show({finished, results in @@ -339,7 +339,7 @@ class SettingsViewController: FormViewController { print("Permissions finished, resetting API!") }) } - + <<< ButtonRow("notificationSettings") { $0.title = "Notification Settings" $0.hidden = Condition(booleanLiteral: !HomeAssistantAPI.sharedInstance.notificationsEnabled) @@ -352,8 +352,8 @@ class SettingsViewController: FormViewController { let _ = vc.navigationController?.popViewController(animated: true) }) } - - +++ Section(){ + + +++ Section() { $0.tag = "reset" $0.hidden = Condition(booleanLiteral: !self.configured) } @@ -361,18 +361,18 @@ class SettingsViewController: FormViewController { $0.title = "Reset" }.cellUpdate { cell, _ in cell.textLabel?.textColor = .red - }.onCellSelection{ cell, row in + }.onCellSelection { _, _ in let alert = UIAlertController(title: "Reset", message: "Your settings will be reset and this device will be unregistered from push notifications as well as removed from your Home Assistant configuration.", preferredStyle: UIAlertControllerStyle.alert) - - alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (action: UIAlertAction!) in + + alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (_) in print("Handle Cancel Logic here") })) - - alert.addAction(UIAlertAction(title: "Reset", style: .destructive, handler: { (action: UIAlertAction!) in + + alert.addAction(UIAlertAction(title: "Reset", style: .destructive, handler: { (_) in print("Handle Ok logic here") self.ResetApp() })) - + self.present(alert, animated: true, completion: nil) } } @@ -382,9 +382,8 @@ class SettingsViewController: FormViewController { // Dispose of any resources that can be recreated. } - - func HomeAssistantDiscovered(_ notification: Notification){ - let discoverySection : Section = self.form.sectionBy(tag: "discoveredInstances")! + func HomeAssistantDiscovered(_ notification: Notification) { + let discoverySection: Section = self.form.sectionBy(tag: "discoveredInstances")! discoverySection.hidden = false discoverySection.evaluateHidden() if let userInfo = (notification as Notification).userInfo as? [String:Any] { @@ -396,10 +395,10 @@ class SettingsViewController: FormViewController { <<< ButtonRow(discoveryInfo.LocationName) { $0.title = discoveryInfo.LocationName $0.cellStyle = UITableViewCellStyle.subtitle - }.cellUpdate { cell, row in + }.cellUpdate { cell, _ in cell.textLabel?.textColor = .black cell.detailTextLabel?.text = detailTextLabel - }.onCellSelection({ cell, row in + }.onCellSelection({ _, _ in let urlRow: URLRow = self.form.rowBy(tag: "baseURL")! urlRow.value = discoveryInfo.BaseURL urlRow.disabled = true @@ -412,7 +411,7 @@ class SettingsViewController: FormViewController { }) self.tableView?.reloadData() } else { - if let readdedRow : ButtonRow = self.form.rowBy(tag: discoveryInfo.LocationName) { + if let readdedRow: ButtonRow = self.form.rowBy(tag: discoveryInfo.LocationName) { readdedRow.hidden = false readdedRow.updateCell() readdedRow.evaluateHidden() @@ -421,21 +420,21 @@ class SettingsViewController: FormViewController { } } - func HomeAssistantUndiscovered(_ notification: Notification){ + func HomeAssistantUndiscovered(_ notification: Notification) { if let userInfo = (notification as Notification).userInfo { let name = userInfo["name"] as! String - if let removingRow : ButtonRow = self.form.rowBy(tag: name) { + if let removingRow: ButtonRow = self.form.rowBy(tag: name) { removingRow.hidden = true removingRow.evaluateHidden() removingRow.updateCell() } } - let discoverySection : Section = self.form.sectionBy(tag: "discoveredInstances")! + let discoverySection: Section = self.form.sectionBy(tag: "discoveredInstances")! discoverySection.hidden = Condition(booleanLiteral: (discoverySection.count < 1)) discoverySection.evaluateHidden() } - func SSEConnectionChange(_ notification: Notification){ + func SSEConnectionChange(_ notification: Notification) { let sseRow: LabelRow = self.form.rowBy(tag: "connectedToSSE")! if notification.name.rawValue == "sse.opened" { sseRow.value = "✔️" @@ -444,8 +443,8 @@ class SettingsViewController: FormViewController { } sseRow.updateCell() } - - func Connected(_ notification: Notification){ + + func Connected(_ notification: Notification) { let iosComponentLoadedRow: LabelRow = self.form.rowBy(tag: "iosComponentLoaded")! iosComponentLoadedRow.value = HomeAssistantAPI.sharedInstance.iosComponentLoaded ? "✔️" : "✖️" iosComponentLoadedRow.updateCell() @@ -456,7 +455,7 @@ class SettingsViewController: FormViewController { notifyPlatformLoadedRow.value = HomeAssistantAPI.sharedInstance.iosNotifyPlatformLoaded ? "✔️" : "✖️" notifyPlatformLoadedRow.updateCell() } - + @IBOutlet var emailInput: UITextField! func emailEntered(_ sender: UIAlertAction) { if let email = emailInput.text { @@ -473,7 +472,7 @@ class SettingsViewController: FormViewController { checkForEmail() } } - + func checkForEmail() { if prefs.bool(forKey: "emailSet") == false || prefs.string(forKey: "userEmail") == nil { print("This is first launch, let's prompt user for email.") @@ -487,7 +486,7 @@ class SettingsViewController: FormViewController { self.present(alert, animated: true, completion: nil) } } - + func saveSettings() { if let urlRow: URLRow = self.form.rowBy(tag: "baseURL") { if let url = urlRow.value { @@ -509,11 +508,11 @@ class SettingsViewController: FormViewController { self.prefs.set(allowAllGroups, forKey: "allowAllGroups") } } - + self.prefs.synchronize() - + let pscope = PermissionScope() - + pscope.addPermission(LocationAlwaysPermission(), message: "We use this to inform\r\nHome Assistant of your device presence.") pscope.addPermission(NotificationsPermission(), @@ -530,22 +529,22 @@ class SettingsViewController: FormViewController { (UIApplication.shared.delegate as! AppDelegate).initAPI() }) } - + func ResetApp() { let bundleId = Bundle.main.bundleIdentifier! UserDefaults.standard.removePersistentDomain(forName: bundleId) UserDefaults.standard.synchronize() self.prefs.removePersistentDomain(forName: bundleId) self.prefs.synchronize() - + _ = HomeAssistantAPI.sharedInstance.removeDevice().then { _ in print("Done with reset!") } } - + func openAbout(_ sender: UIButton) { let aboutView = AboutViewController() - + let navController = UINavigationController(rootViewController: aboutView) self.show(navController, sender: nil) // self.present(navController, animated: true, completion: nil) diff --git a/NotificationContentExtension/MjpegStreamingController.swift b/NotificationContentExtension/MjpegStreamingController.swift index 64a7850c8..458961844 100644 --- a/NotificationContentExtension/MjpegStreamingController.swift +++ b/NotificationContentExtension/MjpegStreamingController.swift @@ -10,70 +10,70 @@ import UIKit open class MjpegStreamingController: NSObject, URLSessionDataDelegate { - + fileprivate enum Status { case stopped case loading case playing } - + fileprivate var receivedData: NSMutableData? fileprivate var dataTask: URLSessionDataTask? fileprivate var session: Foundation.URLSession! fileprivate var status: Status = .stopped - + open var authenticationHandler: ((URLAuthenticationChallenge) -> (Foundation.URLSession.AuthChallengeDisposition, URLCredential?))? - open var didStartLoading: (()->Void)? - open var didFinishLoading: (()->Void)? + open var didStartLoading: (() -> Void)? + open var didFinishLoading: (() -> Void)? open var contentURL: URL? open var imageView: UIImageView - + public init(imageView: UIImageView, sessionConfiguration: URLSessionConfiguration = URLSessionConfiguration.default) { self.imageView = imageView super.init() self.session = Foundation.URLSession(configuration: sessionConfiguration, delegate: self, delegateQueue: nil) } - + public convenience init(imageView: UIImageView, contentURL: URL, sessionConfiguration: URLSessionConfiguration = URLSessionConfiguration.default) { self.init(imageView: imageView, sessionConfiguration: sessionConfiguration) self.contentURL = contentURL } - + deinit { dataTask?.cancel() } - - open func play(url: URL){ + + open func play(url: URL) { if status == .playing || status == .loading { stop() } contentURL = url play() } - + open func play() { - guard let url = contentURL , status == .stopped else { + guard let url = contentURL, status == .stopped else { return } - + status = .loading DispatchQueue.main.async { self.didStartLoading?() } - + receivedData = NSMutableData() let request = URLRequest(url: url) dataTask = session.dataTask(with: request) dataTask?.resume() } - - open func stop(){ + + open func stop() { status = .stopped dataTask?.cancel() } - + // MARK: - NSURLSessionDataDelegate - + open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) { - if let imageData = receivedData , imageData.length > 0, + if let imageData = receivedData, imageData.length > 0, let receivedImage = UIImage(data: imageData as Data) { // I'm creating the UIImage before performing didFinishLoading to minimize the interval // between the actions done by didFinishLoading and the appearance of the first image @@ -81,25 +81,25 @@ open class MjpegStreamingController: NSObject, URLSessionDataDelegate { status = .playing DispatchQueue.main.async { self.didFinishLoading?() } } - + DispatchQueue.main.async { self.imageView.image = receivedImage } } - + receivedData = NSMutableData() completionHandler(.allow) } - + open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { receivedData?.append(data) } - + // MARK: - NSURLSessionTaskDelegate - + open func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { - + var credential: URLCredential? var disposition: Foundation.URLSession.AuthChallengeDisposition = .performDefaultHandling - + if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust { if let trust = challenge.protectionSpace.serverTrust { credential = URLCredential(trust: trust) @@ -108,7 +108,7 @@ open class MjpegStreamingController: NSObject, URLSessionDataDelegate { } else if let onAuthentication = authenticationHandler { (disposition, credential) = onAuthentication(challenge) } - + completionHandler(disposition, credential) } } diff --git a/NotificationContentExtension/NotificationViewController.swift b/NotificationContentExtension/NotificationViewController.swift index 5a77060a1..7d52d6650 100644 --- a/NotificationContentExtension/NotificationViewController.swift +++ b/NotificationContentExtension/NotificationViewController.swift @@ -15,15 +15,15 @@ import MBProgressHUD class NotificationViewController: UIViewController, UNNotificationContentExtension { var hud: MBProgressHUD? = nil - + private var baseURL: String = "" - + let urlConfiguration: URLSessionConfiguration = URLSessionConfiguration.default - + override func viewDidLoad() { super.viewDidLoad() // Do any required interface initialization here. - + let prefs = UserDefaults(suiteName: "group.io.robbie.homeassistant")! if let url = prefs.string(forKey: "baseURL") { baseURL = url @@ -32,7 +32,7 @@ class NotificationViewController: UIViewController, UNNotificationContentExtensi urlConfiguration.httpAdditionalHeaders = ["X-HA-Access": pass] } } - + func didReceive(_ notification: UNNotification) { print("Received a \(notification.request.content.categoryIdentifier) notification type") let hud = MBProgressHUD.showAdded(to: self.view, animated: true) @@ -48,17 +48,17 @@ class NotificationViewController: UIViewController, UNNotificationContentExtensi return } } - + func mapHandler(_ notification: UNNotification) { let haDict = notification.request.content.userInfo["homeassistant"] as! [String:Any] guard let latitudeString = haDict["latitude"] as? String else { return } guard let longitudeString = haDict["longitude"] as? String else { return } let latitude = Double.init(latitudeString)! as CLLocationDegrees let longitude = Double.init(longitudeString)! as CLLocationDegrees - + let mapCoordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude) let span = MKCoordinateSpanMake(0.1, 0.1) - + let options = MKMapSnapshotOptions() options.mapType = .standard options.showsPointsOfInterest = false @@ -66,25 +66,25 @@ class NotificationViewController: UIViewController, UNNotificationContentExtensi options.region = MKCoordinateRegion(center: mapCoordinate, span: span) options.size = self.view.frame.size options.scale = self.view.contentScaleFactor - + let snapshotter = MKMapSnapshotter(options: options) - snapshotter.start() { snapshot, error in - + snapshotter.start() { snapshot, _ in + let image = snapshot!.image - + let pin = MKPinAnnotationView(annotation: nil, reuseIdentifier: "") let pinImage = pin.image - - UIGraphicsBeginImageContextWithOptions(image.size, true, image.scale); - + + UIGraphicsBeginImageContextWithOptions(image.size, true, image.scale) + image.draw(at: CGPoint(x: 0, y: 0)) - + let homePoint = snapshot?.point(for: mapCoordinate) pinImage?.draw(at: homePoint!) - + let finalImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() - + let imageView = UIImageView(image: finalImage) imageView.frame = self.view.frame imageView.contentMode = .scaleAspectFit @@ -93,15 +93,15 @@ class NotificationViewController: UIViewController, UNNotificationContentExtensi self.preferredContentSize = CGSize(width: 0, height: imageView.frame.maxY) } } - + func cameraHandler(_ notification: UNNotification) { guard let entityId = notification.request.content.userInfo["entity_id"] as? String else { return } guard let cameraProxyURL = URL(string: "\(baseURL)/api/camera_proxy_stream/\(entityId)") else { return } - + let imageView = UIImageView() imageView.frame = self.view.frame imageView.contentMode = .scaleAspectFit - + let streamingController = MjpegStreamingController(imageView: imageView, contentURL: cameraProxyURL, sessionConfiguration: urlConfiguration) streamingController.didFinishLoading = { _ in print("Finished loading")