Adds search function for list view

This commit is contained in:
Patrick McDonagh
2018-06-11 10:21:03 -05:00
parent ec2e0b643b
commit 2e08234eef
38 changed files with 991 additions and 823 deletions

View File

@@ -1,93 +0,0 @@
//
// AdminViewController.swift
// pocloud
//
// Created by Patrick McDonagh on 6/6/18.
// Copyright © 2018 patrickjmcd. All rights reserved.
//
import UIKit
import RealmSwift
import PromiseKit
class AdminViewController: UITableViewController {
let realm = try! Realm()
let baseURL = (UIApplication.shared.delegate as! AppDelegate).baseURL
let user = (UIApplication.shared.delegate as! AppDelegate).user
let appAuth = AppAuth()
var companiesWithGateways : Results<Company>?
var companiesNoGateways : Results<Company>?
var selectedCompany : Company?
override func viewDidLoad() {
super.viewDidLoad()
// Get company data from Realm
companiesWithGateways = realm.objects(Company.self).filter("gateways.@count > 0")
companiesNoGateways = realm.objects(Company.self).filter("gateways.@count == 0")
if (companiesWithGateways!.count + companiesNoGateways!.count) == 0{
firstly {
getAllMeshifyData(baseURL: self.baseURL, authToken: self.user!.authToken)
}.done {
self.tableView.reloadData()
}.catch { error in
print("Error getting all meshify data in AdminViewController: \(error)")
}
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return companiesWithGateways?.count ?? 0
} else {
return companiesNoGateways?.count ?? 0
}
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section == 0 {
return "Companies with Devices"
} else {
return "Companies with NO Devices"
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "companyCell", for: indexPath) as! AdminCompanyCell
if indexPath.section == 0 {
cell.companyNameLabel.text = companiesWithGateways![indexPath.row].name
cell.companyCountLabel.text = String(companiesWithGateways![indexPath.row].gateways.count)
} else {
cell.companyNameLabel.text = companiesNoGateways![indexPath.row].name
cell.companyCountLabel.isHidden = true
cell.accessoryType = .none
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 0 {
selectedCompany = companiesWithGateways![indexPath.row]
performSegue(withIdentifier: "openCompanyDetailView", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "openCompanyDetailView" {
let targetVC = segue.destination as! CompanyViewController
targetVC.thisCompany = selectedCompany
}
}
}

View File

@@ -0,0 +1,102 @@
//
// CompanyViewController.swift
// pocloud
//
// Created by Patrick McDonagh on 6/6/18.
// Copyright © 2018 patrickjmcd. All rights reserved.
//
import UIKit
import MapKit
class CompanyDetailViewController: UIViewController, MKMapViewDelegate, UITableViewDataSource, UITableViewDelegate {
@IBOutlet weak var mapView: MKMapView!
@IBOutlet weak var tableView: UITableView!
var thisCompany : Company?
var selectedGateway : Gateway?
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
mapView.delegate = self
title = thisCompany?.name
addMapDot()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let company = thisCompany{
return company.gateways.count
} else {
return 0
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "companyGatewayCell", for: indexPath)
cell.textLabel?.text = thisCompany?.gateways[indexPath.row].name
return cell
}
func addMapDot(){
let coord = CLLocationCoordinate2D(latitude: (thisCompany?.address!.lat)!, longitude: (thisCompany?.address!.long)!)
let gatewayAnnotation = GatewayAnnotation(coordinate: coord, title: (thisCompany?.name)!, subtitle: (thisCompany?.address?.streetAddress)!, gateway: nil)
mapView.addAnnotation(gatewayAnnotation)
let regionRadius: CLLocationDistance = 1000
let coordinateRegion = MKCoordinateRegionMakeWithDistance(coord, regionRadius, regionRadius)
mapView.setRegion(coordinateRegion, animated: true)
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "marker"
if annotation.isKind(of: GatewayAnnotation.self) {
var view: MKMarkerAnnotationView
if let dequeuedView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKMarkerAnnotationView {
dequeuedView.annotation = annotation
view = dequeuedView
} else {
view = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: identifier)
view.canShowCallout = true
view.calloutOffset = CGPoint(x: -5, y: 5)
view.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
}
return view
} else {
return nil
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedGateway = thisCompany?.gateways[indexPath.row]
performSegue(withIdentifier: "openGatewayDetail", sender: self)
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
let location = view.annotation as! GatewayAnnotation
let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving]
location.mapItem().openInMaps(launchOptions: launchOptions)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "openGatewayDetail" {
let destinationVC = segue.destination as! MapDetailViewController
destinationVC.gateway = selectedGateway
}
}
}

View File

@@ -7,96 +7,87 @@
//
import UIKit
import MapKit
import RealmSwift
import PromiseKit
class CompanyViewController: UIViewController, MKMapViewDelegate, UITableViewDataSource, UITableViewDelegate {
@IBOutlet weak var mapView: MKMapView!
@IBOutlet weak var tableView: UITableView!
class CompanyViewController: UITableViewController {
let realm = try! Realm()
let baseURL = (UIApplication.shared.delegate as! AppDelegate).baseURL
let user = (UIApplication.shared.delegate as! AppDelegate).user
let appAuth = AppAuth()
var thisCompany : Company?
var selectedGateway : Gateway?
var companiesWithGateways : Results<Company>?
var companiesNoGateways : Results<Company>?
var selectedCompany : Company?
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
mapView.delegate = self
title = thisCompany?.name
// Get company data from Realm
companiesWithGateways = realm.objects(Company.self).filter("gateways.@count > 0")
companiesNoGateways = realm.objects(Company.self).filter("gateways.@count == 0")
addMapDot()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let company = thisCompany{
return company.gateways.count
} else {
return 0
if (companiesWithGateways!.count + companiesNoGateways!.count) == 0{
firstly {
getAllMeshifyData(baseURL: self.baseURL, authToken: self.user!.authToken)
}.done {
self.tableView.reloadData()
}.catch { error in
print("Error getting all meshify data in CompanyViewController: \(error)")
}
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return companiesWithGateways?.count ?? 0
} else {
return companiesNoGateways?.count ?? 0
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "companyGatewayCell", for: indexPath)
cell.textLabel?.text = thisCompany?.gateways[indexPath.row].name
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section == 0 {
return "Companies with Devices"
} else {
return "Companies with NO Devices"
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "companyCell", for: indexPath) as! AdminCompanyCell
if indexPath.section == 0 {
cell.companyNameLabel.text = companiesWithGateways![indexPath.row].name
cell.companyCountLabel.text = String(companiesWithGateways![indexPath.row].gateways.count)
} else {
cell.companyNameLabel.text = companiesNoGateways![indexPath.row].name
cell.companyCountLabel.isHidden = true
cell.accessoryType = .none
}
return cell
}
func addMapDot(){
let coord = CLLocationCoordinate2D(latitude: (thisCompany?.address!.lat)!, longitude: (thisCompany?.address!.long)!)
let gatewayAnnotation = GatewayAnnotation(coordinate: coord, title: (thisCompany?.name)!, subtitle: (thisCompany?.address?.streetAddress)!, gateway: nil)
mapView.addAnnotation(gatewayAnnotation)
let regionRadius: CLLocationDistance = 1000
let coordinateRegion = MKCoordinateRegionMakeWithDistance(coord, regionRadius, regionRadius)
mapView.setRegion(coordinateRegion, animated: true)
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "marker"
if annotation.isKind(of: GatewayAnnotation.self) {
var view: MKMarkerAnnotationView
if let dequeuedView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKMarkerAnnotationView {
dequeuedView.annotation = annotation
view = dequeuedView
} else {
view = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: identifier)
view.canShowCallout = true
view.calloutOffset = CGPoint(x: -5, y: 5)
view.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
}
return view
} else {
return nil
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 0 {
selectedCompany = companiesWithGateways![indexPath.row]
performSegue(withIdentifier: "openCompanyDetailView", sender: self)
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedGateway = thisCompany?.gateways[indexPath.row]
performSegue(withIdentifier: "openGatewayDetail", sender: self)
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
let location = view.annotation as! GatewayAnnotation
let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving]
location.mapItem().openInMaps(launchOptions: launchOptions)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "openGatewayDetail" {
let destinationVC = segue.destination as! MapDetailViewController
destinationVC.gateway = selectedGateway
if segue.identifier == "openCompanyDetailView" {
let targetVC = segue.destination as! CompanyDetailViewController
targetVC.thisCompany = selectedCompany
}
}
}

View File

@@ -33,6 +33,10 @@ class DeviceDetailViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.estimatedRowHeight = 44
self.tableView.rowHeight = UITableViewAutomaticDimension
ref = Database.database().reference()
let macAddress = String((thisDevice?.macAddress.replacingOccurrences(of: ":", with: "").uppercased().dropLast(4))!)
let deviceTypeName = (thisDevice?.parentDeviceType.first?.name)!
@@ -112,9 +116,18 @@ class DeviceDetailViewController: UITableViewController {
let value = snapshot.value as! NSDictionary
let chanVal = MeshifyValue()
chanVal.name = (value["name"] as? String)!
chanVal.timestamp = Int((value["timestamp"] as? String)!)!
chanVal.value = (value["value"] as? String)!
if let name = value["name"] as? String {
chanVal.name = name
}
if let timestamp = value["timestamp"] as? String {
chanVal.timestamp = Int(Double(timestamp)!)
}
if let readValue = value["value"] as? String {
chanVal.value = readValue
}
let prevChanValue = self.values[chanVal.name]?.value
if prevChanValue != chanVal.value {
self.changedChannelNames.append(chanVal.name)

View File

@@ -28,6 +28,7 @@ class DeviceListViewController: UITableViewController {
var deviceTypes : Results<DeviceType>?
let baseURL = (UIApplication.shared.delegate as! AppDelegate).baseURL
let deviceTypeFilter = NSPredicate(format: "devices.@count > 0 AND NOT name IN %@", ["gen", "mainHP", "M1"])
let ignoreDeviceTypes = ["M1", "Gateway"]
var selectedDevice: Device?
@@ -40,6 +41,8 @@ class DeviceListViewController: UITableViewController {
searchBar.delegate = self
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Log Out", style: .plain, target: self, action: #selector(self.logOut))
SVProgressHUD.show()
@@ -82,6 +85,24 @@ class DeviceListViewController: UITableViewController {
}
func getUniqueDeviceTypeNames() -> [String]{
var deviceTypeNames : [String] = [String]()
if let devicesList = devices {
for d in devicesList {
if let deviceParent = d.parentDeviceType.first {
deviceTypeNames.append(deviceParent.vanityName)
}
}
}
return deviceTypeNames.reduce([], { initialValue, collectionElement in
initialValue.contains(collectionElement) ? initialValue : initialValue + [collectionElement]
})
.filter({ (name) -> Bool in
!self.ignoreDeviceTypes.contains(name)
})
}
@objc func refresh() {
SVProgressHUD.show()
@@ -101,18 +122,17 @@ class DeviceListViewController: UITableViewController {
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
let deviceTypesWithDevices = deviceTypes?.filter(deviceTypeFilter)
return deviceTypesWithDevices?.count ?? 0
return getUniqueDeviceTypeNames().count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let deviceTypesWithDevices = deviceTypes?.filter(deviceTypeFilter)
return deviceTypesWithDevices?[section].devices.count ?? 0
let uniqueDeviceTypes = getUniqueDeviceTypeNames()
let deviceTypesWithDevices = devices?.filter("ANY parentDeviceType.vanityName == %@", uniqueDeviceTypes[section])
return deviceTypesWithDevices?.count ?? 0
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let deviceTypesWithDevices = deviceTypes?.filter(deviceTypeFilter)
return ((deviceTypesWithDevices?.count)! > 0) ? deviceTypesWithDevices?[section].vanityName : "Unknown"
return getUniqueDeviceTypeNames()[section]
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
@@ -124,21 +144,24 @@ class DeviceListViewController: UITableViewController {
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "deviceListCell", for: indexPath)
let deviceTypesWithDevices = deviceTypes?.filter(deviceTypeFilter)
let uniqueDeviceTypes = getUniqueDeviceTypeNames()
let deviceTypesWithDevices = devices?.filter("ANY parentDeviceType.vanityName == %@", uniqueDeviceTypes[indexPath.section]).sorted(byKeyPath: "vanityName")
if (deviceTypesWithDevices?.count)! > 0 {
cell.textLabel?.text = deviceTypesWithDevices?[indexPath.section].devices[indexPath.row].vanityName
cell.textLabel?.text = deviceTypesWithDevices?[indexPath.row].vanityName
cell.accessoryType = .disclosureIndicator
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let deviceTypesWithDevices = deviceTypes?.filter(deviceTypeFilter)
if let thisSection = deviceTypesWithDevices?[indexPath.section] {
selectedDevice = thisSection.devices[indexPath.row]
// print(selectedDevice)
let uniqueDeviceTypes = getUniqueDeviceTypeNames()
let deviceTypesWithDevices = devices?.filter("ANY parentDeviceType.vanityName == %@", uniqueDeviceTypes[indexPath.section]).sorted(byKeyPath: "vanityName")
// let deviceTypesWithDevices = deviceTypes?.filter(deviceTypeFilter)
// if let thisSection = deviceTypesWithDevices?[indexPath.section] {
// selectedDevice = thisSection.devices[indexPath.row]
selectedDevice = deviceTypesWithDevices?[indexPath.row]
performSegue(withIdentifier: "openDeviceDetailView", sender: self)
}
// }
}
@@ -166,16 +189,16 @@ extension DeviceListViewController : UISearchBarDelegate {
if searchBar.text?.count == 0 {
firstly {
self.loadRealmData()
}.then{ _ in
self.loadJSONData()
}.done { _ in
self.tableView.reloadData()
DispatchQueue.main.async {
searchBar.resignFirstResponder()
}
}.catch { error in
print("Error in getting data in DeviceListViewController: \(error)")
}.then{ _ in
self.loadJSONData()
}.done { _ in
self.tableView.reloadData()
DispatchQueue.main.async {
searchBar.resignFirstResponder()
}
}.catch { error in
print("Error in getting data in DeviceListViewController: \(error)")
}
}
}

View File

@@ -13,6 +13,9 @@ class NavigationMenuController: UITableViewController {
let appAuth = AppAuth()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.estimatedRowHeight = 44
self.tableView.rowHeight = UITableViewAutomaticDimension
}

View File

@@ -17,7 +17,9 @@
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>7</string>
<string>9-rc1</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSLocationUsageDescription</key>

View File

@@ -119,10 +119,7 @@
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Map View" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="K2m-on-u83">
<rect key="frame" x="16" y="0.0" width="343" height="44"/>
<constraints>
<constraint firstAttribute="height" constant="44" id="WkR-Ec-bck"/>
</constraints>
<rect key="frame" x="16" y="0.0" width="343" height="43.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
@@ -131,7 +128,7 @@
<constraints>
<constraint firstAttribute="trailing" secondItem="K2m-on-u83" secondAttribute="trailing" constant="16" id="itX-5w-OBv"/>
<constraint firstItem="K2m-on-u83" firstAttribute="leading" secondItem="Zft-87-4vv" secondAttribute="leading" constant="16" id="ov7-hP-RzB"/>
<constraint firstAttribute="bottom" secondItem="K2m-on-u83" secondAttribute="bottom" id="uWk-am-QXU"/>
<constraint firstAttribute="bottom" relation="lessThanOrEqual" secondItem="K2m-on-u83" secondAttribute="bottom" id="uWk-am-QXU"/>
<constraint firstItem="K2m-on-u83" firstAttribute="top" secondItem="Zft-87-4vv" secondAttribute="top" id="v3E-fu-Z3h"/>
</constraints>
</tableViewCellContentView>
@@ -147,10 +144,7 @@
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="List View" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="O2Q-ia-Znc">
<rect key="frame" x="16" y="0.0" width="343" height="44"/>
<constraints>
<constraint firstAttribute="height" constant="44" id="OUu-Sl-qO8"/>
</constraints>
<rect key="frame" x="16" y="0.0" width="343" height="43.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
@@ -159,7 +153,7 @@
<constraints>
<constraint firstItem="O2Q-ia-Znc" firstAttribute="top" secondItem="cHZ-P5-57P" secondAttribute="top" id="6b0-uT-Dyz"/>
<constraint firstAttribute="trailing" secondItem="O2Q-ia-Znc" secondAttribute="trailing" constant="16" id="X35-2D-Vmj"/>
<constraint firstAttribute="bottom" secondItem="O2Q-ia-Znc" secondAttribute="bottom" id="gii-t8-r0I"/>
<constraint firstAttribute="bottom" relation="lessThanOrEqual" secondItem="O2Q-ia-Znc" secondAttribute="bottom" id="gii-t8-r0I"/>
<constraint firstItem="O2Q-ia-Znc" firstAttribute="leading" secondItem="cHZ-P5-57P" secondAttribute="leading" constant="16" id="tNz-Jj-6c9"/>
</constraints>
</tableViewCellContentView>
@@ -175,10 +169,7 @@
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Company View" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="PBz-lV-jm5">
<rect key="frame" x="16" y="0.0" width="343" height="44"/>
<constraints>
<constraint firstAttribute="height" constant="44" id="W4g-rH-3kB"/>
</constraints>
<rect key="frame" x="16" y="0.0" width="343" height="43.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
@@ -187,7 +178,7 @@
<constraints>
<constraint firstItem="PBz-lV-jm5" firstAttribute="top" secondItem="uOu-qn-Bsk" secondAttribute="top" id="eFS-1d-xye"/>
<constraint firstItem="PBz-lV-jm5" firstAttribute="leading" secondItem="uOu-qn-Bsk" secondAttribute="leading" constant="16" id="uJV-EL-4pQ"/>
<constraint firstAttribute="bottom" secondItem="PBz-lV-jm5" secondAttribute="bottom" id="y0g-od-TRr"/>
<constraint firstAttribute="bottom" relation="lessThanOrEqual" secondItem="PBz-lV-jm5" secondAttribute="bottom" id="y0g-od-TRr"/>
<constraint firstAttribute="trailing" secondItem="PBz-lV-jm5" secondAttribute="trailing" constant="16" id="y7M-Vh-JFu"/>
</constraints>
</tableViewCellContentView>
@@ -218,7 +209,7 @@
<!--Admin View-->
<scene sceneID="luK-QG-5Bk">
<objects>
<tableViewController title="Admin View" id="gRf-OH-LM3" customClass="AdminViewController" customModule="pocloud" customModuleProvider="target" sceneMemberID="viewController">
<tableViewController title="Admin View" id="gRf-OH-LM3" customClass="CompanyViewController" customModule="pocloud" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="pRZ-8h-aCt">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@@ -241,7 +232,7 @@
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="cnt" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="16b-fu-GPA" customClass="PillUILabel" customModule="pocloud" customModuleProvider="target">
<rect key="frame" x="278.5" y="8.5" width="46.5" height="26.5"/>
<rect key="frame" x="278.5" y="11.5" width="46.5" height="20.5"/>
<color key="backgroundColor" red="0.0" green="0.32852089410000002" blue="0.57488495110000004" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
@@ -297,7 +288,7 @@
<!--Title-->
<scene sceneID="zaO-o6-5qR">
<objects>
<viewController id="1Oj-LF-SeF" customClass="CompanyViewController" customModule="pocloud" customModuleProvider="target" sceneMemberID="viewController">
<viewController id="1Oj-LF-SeF" customClass="CompanyDetailViewController" customModule="pocloud" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="GRC-ek-5fe">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@@ -412,13 +403,13 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<mapView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" mapType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="xug-gE-FQz">
<rect key="frame" x="0.0" y="65" width="375" height="200"/>
<rect key="frame" x="0.0" y="109" width="375" height="200"/>
<constraints>
<constraint firstAttribute="height" constant="200" id="tu9-2Y-yHN"/>
</constraints>
</mapView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="GatewayName" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="izu-lT-xWY">
<rect key="frame" x="8" y="20" width="359" height="45"/>
<rect key="frame" x="8" y="64" width="359" height="45"/>
<constraints>
<constraint firstAttribute="height" constant="45" id="jbO-lj-xVg"/>
</constraints>
@@ -427,7 +418,7 @@
<nil key="highlightedColor"/>
</label>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="tRH-fh-elp">
<rect key="frame" x="0.0" y="275" width="375" height="392"/>
<rect key="frame" x="0.0" y="319" width="375" height="304"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="dataViewCell" rowHeight="60" id="5Sz-TR-mVj" customClass="MapDetailDeviceCell" customModule="pocloud" customModuleProvider="target">
@@ -520,37 +511,33 @@
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="8Um-Bu-9sz">
<rect key="frame" x="16" y="0.0" width="343" height="44"/>
<rect key="frame" x="16" y="0.0" width="343" height="43.5"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Bkh-Zy-Gmc">
<rect key="frame" x="0.0" y="0.0" width="172" height="44"/>
<constraints>
<constraint firstAttribute="width" constant="172" id="RRS-6S-a7K"/>
</constraints>
<rect key="frame" x="0.0" y="0.0" width="171.5" height="43.5"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="14"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="right" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="EXp-nl-Xlu">
<rect key="frame" x="172" y="0.0" width="171" height="44"/>
<rect key="frame" x="171.5" y="0.0" width="171.5" height="43.5"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="EXp-nl-Xlu" firstAttribute="top" secondItem="8Um-Bu-9sz" secondAttribute="top" id="9Fj-fN-yuC"/>
<constraint firstAttribute="bottom" secondItem="Bkh-Zy-Gmc" secondAttribute="bottom" id="GU8-9u-iwe"/>
<constraint firstAttribute="bottom" secondItem="EXp-nl-Xlu" secondAttribute="bottom" id="cd8-j2-5wB"/>
<constraint firstItem="Bkh-Zy-Gmc" firstAttribute="top" secondItem="8Um-Bu-9sz" secondAttribute="top" id="hsq-tb-wgL"/>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="44" id="pNb-PY-jok"/>
<constraint firstItem="EXp-nl-Xlu" firstAttribute="width" secondItem="Bkh-Zy-Gmc" secondAttribute="width" id="WFF-y6-e24"/>
<constraint firstAttribute="bottom" relation="lessThanOrEqual" secondItem="EXp-nl-Xlu" secondAttribute="bottom" id="bXa-Ey-uWU"/>
<constraint firstItem="EXp-nl-Xlu" firstAttribute="top" secondItem="8Um-Bu-9sz" secondAttribute="top" id="ub8-1t-95f"/>
</constraints>
</stackView>
</subviews>
<constraints>
<constraint firstItem="8Um-Bu-9sz" firstAttribute="top" secondItem="u2w-Yy-Exm" secondAttribute="top" id="5QW-f5-FX9"/>
<constraint firstItem="8Um-Bu-9sz" firstAttribute="leading" secondItem="u2w-Yy-Exm" secondAttribute="leading" constant="16" id="DTN-Mt-MOn"/>
<constraint firstAttribute="trailing" secondItem="8Um-Bu-9sz" secondAttribute="trailing" constant="16" id="Xho-aE-Uhw"/>
<constraint firstItem="8Um-Bu-9sz" firstAttribute="top" secondItem="u2w-Yy-Exm" secondAttribute="top" id="4RE-WM-Oiu"/>
<constraint firstAttribute="bottom" relation="lessThanOrEqual" secondItem="8Um-Bu-9sz" secondAttribute="bottom" id="5dq-rd-hVI"/>
<constraint firstAttribute="trailing" secondItem="8Um-Bu-9sz" secondAttribute="trailing" constant="16" id="HoX-Eq-hZq"/>
<constraint firstItem="8Um-Bu-9sz" firstAttribute="leading" secondItem="u2w-Yy-Exm" secondAttribute="leading" constant="16" id="m6D-Tr-TBa"/>
</constraints>
</tableViewCellContentView>
<connections>
@@ -752,7 +739,10 @@
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Mlm-Lp-0uP">
<rect key="frame" x="287" y="300" width="80" height="30"/>
<rect key="frame" x="277" y="300" width="90" height="30"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="90" id="DFj-0N-UCR"/>
</constraints>
<state key="normal" title="View Graph"/>
<connections>
<segue destination="sJg-Af-FtE" kind="show" identifier="openHistoryGraph" id="WaU-6H-sQq"/>
@@ -770,6 +760,7 @@
<constraint firstAttribute="trailingMargin" secondItem="qKa-BE-rae" secondAttribute="trailing" id="N8l-nU-Wfp"/>
<constraint firstItem="UQ2-66-Iuf" firstAttribute="top" secondItem="Q4o-w1-JdP" secondAttribute="bottom" constant="8" id="OMk-cW-txI"/>
<constraint firstItem="M2H-Lw-iw3" firstAttribute="trailing" secondItem="Eh7-ay-CB3" secondAttribute="trailing" id="Owt-WR-jEW"/>
<constraint firstItem="Mlm-Lp-0uP" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="s1w-I3-Ih9" secondAttribute="leading" constant="20" symbolic="YES" id="T6q-nx-3Al"/>
<constraint firstItem="M2H-Lw-iw3" firstAttribute="top" secondItem="7j2-Cq-PoN" secondAttribute="bottom" id="Wre-RL-KKv"/>
<constraint firstItem="hri-QF-EMo" firstAttribute="top" secondItem="UQ2-66-Iuf" secondAttribute="bottom" id="X8X-hY-04u"/>
<constraint firstItem="M2H-Lw-iw3" firstAttribute="leading" secondItem="Eh7-ay-CB3" secondAttribute="leading" id="YRv-Ke-HWg"/>
@@ -812,7 +803,7 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="qLG-JD-OG3" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3004" y="531"/>
<point key="canvasLocation" x="3004" y="530.28485757121439"/>
</scene>
<!--History Graph View Controller-->
<scene sceneID="WkV-VI-zTb">
@@ -943,8 +934,8 @@
</resources>
<inferredMetricsTieBreakers>
<segue reference="9Om-lw-Jgn"/>
<segue reference="wUb-ND-zk7"/>
<segue reference="DQm-0d-brY"/>
<segue reference="4nz-VA-pdT"/>
<segue reference="bJo-JM-CaN"/>
<segue reference="LUR-lb-5qK"/>
</inferredMetricsTieBreakers>
</document>