RileyLinkDeviceTableViewController.swift 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  1. //
  2. // RileyLinkDeviceTableViewController.swift
  3. // Naterade
  4. //
  5. // Created by Nathan Racklyeft on 3/5/16.
  6. // Copyright © 2016 Nathan Racklyeft. All rights reserved.
  7. //
  8. import UIKit
  9. import LoopKitUI
  10. import RileyLinkBLEKit
  11. import RileyLinkKit
  12. import os.log
  13. let CellIdentifier = "Cell"
  14. public class RileyLinkSwitch: UISwitch {
  15. public var index: Int = 0
  16. public var section: Int = 0
  17. }
  18. public class RileyLinkDeviceTableViewController: UITableViewController {
  19. private let log = OSLog(category: "RileyLinkDeviceTableViewController")
  20. public let device: RileyLinkDevice
  21. private var bleRSSI: Int?
  22. private var firmwareVersion: String? {
  23. didSet {
  24. guard isViewLoaded else {
  25. return
  26. }
  27. cellForRow(.version)?.detailTextLabel?.text = firmwareVersion
  28. }
  29. }
  30. private var fw_hw: String? {
  31. didSet {
  32. guard isViewLoaded else {
  33. return
  34. }
  35. cellForRow(.orl)?.detailTextLabel?.text = fw_hw
  36. }
  37. }
  38. private var uptime: TimeInterval? {
  39. didSet {
  40. guard isViewLoaded else {
  41. return
  42. }
  43. cellForRow(.uptime)?.setDetailAge(uptime)
  44. }
  45. }
  46. private var battery: String? {
  47. didSet {
  48. guard isViewLoaded else {
  49. return
  50. }
  51. cellForRow(.battery)?.setDetailBatteryLevel(battery)
  52. }
  53. }
  54. private var frequency: Measurement<UnitFrequency>? {
  55. didSet {
  56. guard isViewLoaded else {
  57. return
  58. }
  59. cellForRow(.frequency)?.setDetailFrequency(frequency, formatter: frequencyFormatter)
  60. }
  61. }
  62. var rssiFetchTimer: Timer? {
  63. willSet {
  64. rssiFetchTimer?.invalidate()
  65. }
  66. }
  67. private lazy var frequencyFormatter: MeasurementFormatter = {
  68. let formatter = MeasurementFormatter()
  69. formatter.numberFormatter = decimalFormatter
  70. return formatter
  71. }()
  72. private var appeared = false
  73. public init(device: RileyLinkDevice) {
  74. self.device = device
  75. super.init(style: .grouped)
  76. updateDeviceStatus()
  77. }
  78. required public init?(coder aDecoder: NSCoder) {
  79. fatalError("init(coder:) has not been implemented")
  80. }
  81. public override func viewDidLoad() {
  82. super.viewDidLoad()
  83. title = device.name
  84. self.observe()
  85. }
  86. @objc func updateRSSI() {
  87. device.readRSSI()
  88. }
  89. func updateDeviceStatus() {
  90. device.getStatus { (status) in
  91. DispatchQueue.main.async {
  92. self.firmwareVersion = status.firmwareDescription
  93. self.fw_hw = status.fw_hw
  94. self.ledOn = status.ledOn
  95. self.vibrationOn = status.vibrationOn
  96. self.voltage = status.voltage
  97. self.tableView.reloadData()
  98. }
  99. }
  100. }
  101. func updateUptime() {
  102. device.runSession(withName: "Get stats for uptime") { (session) in
  103. do {
  104. let statistics = try session.getRileyLinkStatistics()
  105. DispatchQueue.main.async {
  106. self.uptime = statistics.uptime
  107. }
  108. } catch let error {
  109. self.log.error("Failed to get stats for uptime: %{public}@", String(describing: error))
  110. }
  111. }
  112. }
  113. func updateBatteryLevel() {
  114. device.runSession(withName: "Get battery level") { (session) in
  115. let batteryLevel = self.device.getBatterylevel()
  116. DispatchQueue.main.async {
  117. self.battery = batteryLevel
  118. }
  119. }
  120. }
  121. func orangeClose() {
  122. device.runSession(withName: "Orange Action Close") { (session) in
  123. self.device.orangeClose()
  124. }
  125. }
  126. func orangeReadSet() {
  127. device.runSession(withName: "orange Read Set") { (session) in
  128. self.device.orangeReadSet()
  129. }
  130. }
  131. func orangeReadVDC() {
  132. device.runSession(withName: "orange Read Set") { (session) in
  133. self.device.orangeReadVDC()
  134. }
  135. }
  136. func writePSW() {
  137. device.runSession(withName: "Orange Action PSW") { (session) in
  138. self.device.orangeWritePwd()
  139. }
  140. }
  141. func orangeAction(index: Int) {
  142. device.runSession(withName: "Orange Action \(index)") { (session) in
  143. self.device.orangeAction(mode: index)
  144. }
  145. }
  146. func orangeAction(index: Int, open: Bool) {
  147. device.runSession(withName: "Orange Set Action \(index)") { (session) in
  148. self.device.orangeSetAction(index: index, open: open)
  149. }
  150. }
  151. func updateFrequency() {
  152. device.runSession(withName: "Get base frequency") { (session) in
  153. do {
  154. let frequency = try session.readBaseFrequency()
  155. DispatchQueue.main.async {
  156. self.frequency = frequency
  157. }
  158. } catch let error {
  159. self.log.error("Failed to get base frequency: %{public}@", String(describing: error))
  160. }
  161. }
  162. }
  163. // References to registered notification center observers
  164. private var notificationObservers: [Any] = []
  165. deinit {
  166. for observer in notificationObservers {
  167. NotificationCenter.default.removeObserver(observer)
  168. }
  169. }
  170. private func observe() {
  171. let center = NotificationCenter.default
  172. let mainQueue = OperationQueue.main
  173. notificationObservers = [
  174. center.addObserver(forName: .DeviceNameDidChange, object: device, queue: mainQueue) { [weak self] (note) -> Void in
  175. if let cell = self?.cellForRow(.customName) {
  176. cell.detailTextLabel?.text = self?.device.name
  177. }
  178. self?.title = self?.device.name
  179. },
  180. center.addObserver(forName: .DeviceConnectionStateDidChange, object: device, queue: mainQueue) { [weak self] (note) -> Void in
  181. if let cell = self?.cellForRow(.connection) {
  182. cell.detailTextLabel?.text = self?.device.peripheralState.description
  183. }
  184. },
  185. center.addObserver(forName: .DeviceRSSIDidChange, object: device, queue: mainQueue) { [weak self] (note) -> Void in
  186. self?.bleRSSI = note.userInfo?[RileyLinkDevice.notificationRSSIKey] as? Int
  187. if let cell = self?.cellForRow(.rssi), let formatter = self?.integerFormatter {
  188. cell.setDetailRSSI(self?.bleRSSI, formatter: formatter)
  189. }
  190. },
  191. center.addObserver(forName: .DeviceDidStartIdle, object: device, queue: mainQueue) { [weak self] (note) in
  192. self?.updateDeviceStatus()
  193. },
  194. center.addObserver(forName: .DeviceFW_HWChange, object: device, queue: mainQueue) { [weak self] (note) in
  195. self?.updateDeviceStatus()
  196. },
  197. ]
  198. }
  199. public override func viewWillAppear(_ animated: Bool) {
  200. super.viewWillAppear(animated)
  201. if appeared {
  202. tableView.reloadData()
  203. }
  204. rssiFetchTimer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(updateRSSI), userInfo: nil, repeats: true)
  205. appeared = true
  206. updateRSSI()
  207. updateFrequency()
  208. updateUptime()
  209. updateBatteryLevel()
  210. writePSW()
  211. orangeReadSet()
  212. orangeReadVDC()
  213. orangeAction(index: 9)
  214. }
  215. public override func viewDidDisappear(_ animated: Bool) {
  216. super.viewDidDisappear(animated)
  217. if redOn || yellowOn {
  218. orangeAction(index: 3)
  219. }
  220. if shakeOn {
  221. orangeAction(index: 5)
  222. }
  223. }
  224. public override func viewWillDisappear(_ animated: Bool) {
  225. super.viewWillDisappear(animated)
  226. rssiFetchTimer = nil
  227. }
  228. // MARK: - Formatters
  229. private lazy var dateFormatter: DateFormatter = {
  230. let dateFormatter = DateFormatter()
  231. dateFormatter.dateStyle = .none
  232. dateFormatter.timeStyle = .medium
  233. return dateFormatter
  234. }()
  235. private lazy var integerFormatter = NumberFormatter()
  236. private lazy var measurementFormatter: MeasurementFormatter = {
  237. let formatter = MeasurementFormatter()
  238. formatter.numberFormatter = decimalFormatter
  239. return formatter
  240. }()
  241. private lazy var decimalFormatter: NumberFormatter = {
  242. let decimalFormatter = NumberFormatter()
  243. decimalFormatter.numberStyle = .decimal
  244. decimalFormatter.minimumSignificantDigits = 5
  245. return decimalFormatter
  246. }()
  247. // MARK: - Table view data source
  248. private enum Section: Int, CaseCountable {
  249. case device
  250. case alert
  251. case configureCommand
  252. case commands
  253. }
  254. private enum AlertRow: Int, CaseCountable {
  255. case battery
  256. case voltage
  257. }
  258. private enum DeviceRow: Int, CaseCountable {
  259. case customName
  260. case version
  261. case rssi
  262. case connection
  263. case uptime
  264. case frequency
  265. case battery
  266. case orl
  267. case voltage
  268. }
  269. private enum CommandRow: Int, CaseCountable {
  270. case yellow
  271. case red
  272. case shake
  273. }
  274. private enum ConfigureCommandRow: Int, CaseCountable {
  275. case led
  276. case vibration
  277. }
  278. private func cellForRow(_ row: DeviceRow) -> UITableViewCell? {
  279. return tableView.cellForRow(at: IndexPath(row: row.rawValue, section: Section.device.rawValue))
  280. }
  281. private func cellForRow(_ row: CommandRow) -> UITableViewCell? {
  282. return tableView.cellForRow(at: IndexPath(row: row.rawValue, section: Section.commands.rawValue))
  283. }
  284. public override func numberOfSections(in tableView: UITableView) -> Int {
  285. return Section.count
  286. }
  287. public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  288. switch Section(rawValue: section)! {
  289. case .device:
  290. return DeviceRow.count
  291. case .commands:
  292. return CommandRow.count
  293. case .configureCommand:
  294. return ConfigureCommandRow.count
  295. case .alert:
  296. return AlertRow.count
  297. }
  298. }
  299. @objc
  300. func switchAction(sender: RileyLinkSwitch) {
  301. switch Section(rawValue: sender.section)! {
  302. case .commands:
  303. switch CommandRow(rawValue: sender.index)! {
  304. case .yellow:
  305. if sender.isOn {
  306. orangeAction(index: 1)
  307. } else {
  308. orangeAction(index: 3)
  309. }
  310. yellowOn = sender.isOn
  311. redOn = false
  312. case .red:
  313. if sender.isOn {
  314. orangeAction(index: 2)
  315. } else {
  316. orangeAction(index: 3)
  317. }
  318. yellowOn = false
  319. redOn = sender.isOn
  320. case .shake:
  321. if sender.isOn {
  322. orangeAction(index: 4)
  323. } else {
  324. orangeAction(index: 5)
  325. }
  326. shakeOn = sender.isOn
  327. }
  328. case .configureCommand:
  329. switch ConfigureCommandRow(rawValue: sender.index)! {
  330. case .led:
  331. orangeAction(index: 0, open: sender.isOn)
  332. ledOn = sender.isOn
  333. case .vibration:
  334. orangeAction(index: 1, open: sender.isOn)
  335. vibrationOn = sender.isOn
  336. }
  337. default:
  338. break
  339. }
  340. tableView.reloadData()
  341. }
  342. public override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
  343. return 45
  344. }
  345. var yellowOn = false
  346. var redOn = false
  347. var shakeOn = false
  348. private var ledOn: Bool = false
  349. private var vibrationOn: Bool = false
  350. var voltage = ""
  351. public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  352. let cell: UITableViewCell
  353. if let reusableCell = tableView.dequeueReusableCell(withIdentifier: CellIdentifier) {
  354. cell = reusableCell
  355. } else {
  356. cell = UITableViewCell(style: .value1, reuseIdentifier: CellIdentifier)
  357. let switchView = RileyLinkSwitch()
  358. switchView.tag = 10000
  359. switchView.addTarget(self, action: #selector(switchAction(sender:)), for: .valueChanged)
  360. switchView.frame = CGRect(x: tableView.frame.width - 51 - 20, y: 7, width: 51, height: 31)
  361. cell.contentView.addSubview(switchView)
  362. }
  363. let switchView = cell.contentView.viewWithTag(10000) as? RileyLinkSwitch
  364. switchView?.isHidden = true
  365. switchView?.index = indexPath.row
  366. switchView?.section = indexPath.section
  367. cell.accessoryType = .none
  368. switch Section(rawValue: indexPath.section)! {
  369. case .device:
  370. switch DeviceRow(rawValue: indexPath.row)! {
  371. case .customName:
  372. cell.textLabel?.text = LocalizedString("Name", comment: "The title of the cell showing device name")
  373. cell.detailTextLabel?.text = device.name
  374. cell.accessoryType = .disclosureIndicator
  375. case .version:
  376. cell.textLabel?.text = LocalizedString("Firmware", comment: "The title of the cell showing firmware version")
  377. cell.detailTextLabel?.text = firmwareVersion
  378. case .connection:
  379. cell.textLabel?.text = LocalizedString("Connection State", comment: "The title of the cell showing BLE connection state")
  380. cell.detailTextLabel?.text = device.peripheralState.description
  381. case .rssi:
  382. cell.textLabel?.text = LocalizedString("Signal Strength", comment: "The title of the cell showing BLE signal strength (RSSI)")
  383. cell.setDetailRSSI(bleRSSI, formatter: integerFormatter)
  384. case .uptime:
  385. cell.textLabel?.text = LocalizedString("Uptime", comment: "The title of the cell showing uptime")
  386. cell.setDetailAge(uptime)
  387. case .frequency:
  388. cell.textLabel?.text = LocalizedString("Frequency", comment: "The title of the cell showing current rileylink frequency")
  389. cell.setDetailFrequency(frequency, formatter: frequencyFormatter)
  390. case .battery:
  391. cell.textLabel?.text = NSLocalizedString("Battery level", comment: "The title of the cell showing battery level")
  392. cell.setDetailBatteryLevel(battery)
  393. case .orl:
  394. cell.textLabel?.text = NSLocalizedString("ORL", comment: "The title of the cell showing ORL")
  395. cell.detailTextLabel?.text = fw_hw
  396. case .voltage:
  397. cell.textLabel?.text = NSLocalizedString("Voltage", comment: "The title of the cell showing ORL")
  398. cell.detailTextLabel?.text = voltage
  399. }
  400. case .alert:
  401. switch AlertRow(rawValue: indexPath.row)! {
  402. case .battery:
  403. var value = "OFF"
  404. let v = UserDefaults.standard.integer(forKey: "battery_alert_value")
  405. if v != 0 {
  406. value = "\(v)%"
  407. }
  408. cell.accessoryType = .disclosureIndicator
  409. cell.textLabel?.text = NSLocalizedString("Low Battery Alert", comment: "The title of the cell showing battery level")
  410. cell.detailTextLabel?.text = "\(value)"
  411. case .voltage:
  412. var value = "OFF"
  413. let v = UserDefaults.standard.double(forKey: "voltage_alert_value")
  414. if v != 0 {
  415. value = String(format: "%.1f%", v)
  416. }
  417. cell.accessoryType = .disclosureIndicator
  418. cell.textLabel?.text = NSLocalizedString("Low Voltage Alert", comment: "The title of the cell showing voltage level")
  419. cell.detailTextLabel?.text = "\(value)"
  420. }
  421. case .commands:
  422. cell.accessoryType = .disclosureIndicator
  423. cell.detailTextLabel?.text = nil
  424. switch CommandRow(rawValue: indexPath.row)! {
  425. case .yellow:
  426. switchView?.isHidden = false
  427. cell.accessoryType = .none
  428. switchView?.isOn = yellowOn
  429. cell.textLabel?.text = NSLocalizedString("Lighten Yellow LED", comment: "The title of the cell showing Lighten Yellow LED")
  430. case .red:
  431. switchView?.isHidden = false
  432. cell.accessoryType = .none
  433. switchView?.isOn = redOn
  434. cell.textLabel?.text = NSLocalizedString("Lighten Red LED", comment: "The title of the cell showing Lighten Red LED")
  435. case .shake:
  436. switchView?.isHidden = false
  437. switchView?.isOn = shakeOn
  438. cell.accessoryType = .none
  439. cell.textLabel?.text = NSLocalizedString("Test Vibrator", comment: "The title of the cell showing Test Vibrator")
  440. }
  441. case .configureCommand:
  442. switch ConfigureCommandRow(rawValue: indexPath.row)! {
  443. case .led:
  444. switchView?.isHidden = false
  445. switchView?.isOn = ledOn
  446. cell.accessoryType = .none
  447. cell.textLabel?.text = NSLocalizedString("Enable Connection State LED", comment: "The title of the cell showing Stop Vibrator")
  448. case .vibration:
  449. switchView?.isHidden = false
  450. switchView?.isOn = vibrationOn
  451. cell.accessoryType = .none
  452. cell.textLabel?.text = NSLocalizedString("Enable Connection State Vibrator", comment: "The title of the cell showing Stop Vibrator")
  453. }
  454. }
  455. return cell
  456. }
  457. public override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
  458. switch Section(rawValue: section)! {
  459. case .device:
  460. return LocalizedString("Device", comment: "The title of the section describing the device")
  461. case .commands:
  462. return LocalizedString("Test Commands", comment: "The title of the section describing commands")
  463. case .configureCommand:
  464. return LocalizedString("Configure Commands", comment: "The title of the section describing commands")
  465. case .alert:
  466. return LocalizedString("Alert", comment: "The title of the section describing commands")
  467. }
  468. }
  469. // MARK: - UITableViewDelegate
  470. public override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
  471. switch Section(rawValue: indexPath.section)! {
  472. case .device:
  473. switch DeviceRow(rawValue: indexPath.row)! {
  474. case .customName:
  475. return true
  476. default:
  477. return false
  478. }
  479. case .commands:
  480. return device.peripheralState == .connected
  481. case .configureCommand:
  482. return device.peripheralState == .connected
  483. case .alert:
  484. return true
  485. }
  486. }
  487. public override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
  488. switch Section(rawValue: indexPath.section)! {
  489. case .device:
  490. switch DeviceRow(rawValue: indexPath.row)! {
  491. case .customName:
  492. let vc = TextFieldTableViewController()
  493. if let cell = tableView.cellForRow(at: indexPath) {
  494. vc.title = cell.textLabel?.text
  495. vc.value = device.name
  496. vc.delegate = self
  497. vc.keyboardType = .default
  498. }
  499. show(vc, sender: indexPath)
  500. default:
  501. break
  502. }
  503. case .commands:
  504. break
  505. case .configureCommand:
  506. break
  507. case .alert:
  508. switch AlertRow(rawValue: indexPath.row)! {
  509. case .battery:
  510. let alert = UIAlertController.init(title: "Battery level Alert", message: nil, preferredStyle: .actionSheet)
  511. let action = UIAlertAction.init(title: "OFF", style: .default) { _ in
  512. UserDefaults.standard.setValue(0, forKey: "battery_alert_value")
  513. self.tableView.reloadData()
  514. }
  515. let action1 = UIAlertAction.init(title: "20", style: .default) { _ in
  516. UserDefaults.standard.setValue(20, forKey: "battery_alert_value")
  517. self.tableView.reloadData()
  518. }
  519. let action2 = UIAlertAction.init(title: "30", style: .default) { _ in
  520. UserDefaults.standard.setValue(30, forKey: "battery_alert_value")
  521. self.tableView.reloadData()
  522. }
  523. let action3 = UIAlertAction.init(title: "40", style: .default) { _ in
  524. UserDefaults.standard.setValue(40, forKey: "battery_alert_value")
  525. self.tableView.reloadData()
  526. }
  527. let action4 = UIAlertAction.init(title: "50", style: .default) { _ in
  528. UserDefaults.standard.setValue(50, forKey: "battery_alert_value")
  529. self.tableView.reloadData()
  530. }
  531. alert.addAction(action)
  532. alert.addAction(action1)
  533. alert.addAction(action2)
  534. alert.addAction(action3)
  535. alert.addAction(action4)
  536. present(alert, animated: true, completion: nil)
  537. case .voltage:
  538. let alert = UIAlertController.init(title: "Voltage level Alert", message: nil, preferredStyle: .actionSheet)
  539. let action = UIAlertAction.init(title: "OFF", style: .default) { _ in
  540. UserDefaults.standard.setValue(0, forKey: "voltage_alert_value")
  541. self.tableView.reloadData()
  542. }
  543. let action1 = UIAlertAction.init(title: "2.4", style: .default) { _ in
  544. UserDefaults.standard.setValue(2.4, forKey: "voltage_alert_value")
  545. self.tableView.reloadData()
  546. }
  547. let action2 = UIAlertAction.init(title: "2.5", style: .default) { _ in
  548. UserDefaults.standard.setValue(2.5, forKey: "voltage_alert_value")
  549. self.tableView.reloadData()
  550. }
  551. let action3 = UIAlertAction.init(title: "2.6", style: .default) { _ in
  552. UserDefaults.standard.setValue(2.6, forKey: "voltage_alert_value")
  553. self.tableView.reloadData()
  554. }
  555. let action4 = UIAlertAction.init(title: "2.7", style: .default) { _ in
  556. UserDefaults.standard.setValue(2.7, forKey: "voltage_alert_value")
  557. self.tableView.reloadData()
  558. }
  559. let action5 = UIAlertAction.init(title: "2.8", style: .default) { _ in
  560. UserDefaults.standard.setValue(2.8, forKey: "voltage_alert_value")
  561. self.tableView.reloadData()
  562. }
  563. let action6 = UIAlertAction.init(title: "2.9", style: .default) { _ in
  564. UserDefaults.standard.setValue(2.9, forKey: "voltage_alert_value")
  565. self.tableView.reloadData()
  566. }
  567. let action7 = UIAlertAction.init(title: "3.0", style: .default) { _ in
  568. UserDefaults.standard.setValue(3.0, forKey: "voltage_alert_value")
  569. self.tableView.reloadData()
  570. }
  571. alert.addAction(action)
  572. alert.addAction(action1)
  573. alert.addAction(action2)
  574. alert.addAction(action3)
  575. alert.addAction(action4)
  576. alert.addAction(action5)
  577. alert.addAction(action6)
  578. alert.addAction(action7)
  579. present(alert, animated: true, completion: nil)
  580. }
  581. }
  582. }
  583. }
  584. extension RileyLinkDeviceTableViewController: TextFieldTableViewControllerDelegate {
  585. public func textFieldTableViewControllerDidReturn(_ controller: TextFieldTableViewController) {
  586. _ = navigationController?.popViewController(animated: true)
  587. }
  588. public func textFieldTableViewControllerDidEndEditing(_ controller: TextFieldTableViewController) {
  589. if let indexPath = tableView.indexPathForSelectedRow {
  590. switch Section(rawValue: indexPath.section)! {
  591. case .device:
  592. switch DeviceRow(rawValue: indexPath.row)! {
  593. case .customName:
  594. device.setCustomName(controller.value!)
  595. default:
  596. break
  597. }
  598. default:
  599. break
  600. }
  601. }
  602. }
  603. }
  604. private extension TimeInterval {
  605. func format(using units: NSCalendar.Unit) -> String? {
  606. let formatter = DateComponentsFormatter()
  607. formatter.allowedUnits = units
  608. formatter.unitsStyle = .full
  609. formatter.zeroFormattingBehavior = .dropLeading
  610. formatter.maximumUnitCount = 2
  611. return formatter.string(from: self)
  612. }
  613. }
  614. private extension UITableViewCell {
  615. func setDetailDate(_ date: Date?, formatter: DateFormatter) {
  616. if let date = date {
  617. detailTextLabel?.text = formatter.string(from: date)
  618. } else {
  619. detailTextLabel?.text = "-"
  620. }
  621. }
  622. func setDetailRSSI(_ decibles: Int?, formatter: NumberFormatter) {
  623. detailTextLabel?.text = formatter.decibleString(from: decibles) ?? "-"
  624. }
  625. func setDetailAge(_ age: TimeInterval?) {
  626. if let age = age {
  627. detailTextLabel?.text = age.format(using: [.day, .hour, .minute])
  628. } else {
  629. detailTextLabel?.text = ""
  630. }
  631. }
  632. func setDetailBatteryLevel(_ batteryLevel: String?) {
  633. if let unwrappedBatteryLevel = batteryLevel {
  634. detailTextLabel?.text = unwrappedBatteryLevel + " %"
  635. } else {
  636. detailTextLabel?.text = ""
  637. }
  638. }
  639. func setDetailFrequency(_ frequency: Measurement<UnitFrequency>?, formatter: MeasurementFormatter) {
  640. if let frequency = frequency {
  641. detailTextLabel?.text = formatter.string(from: frequency)
  642. } else {
  643. detailTextLabel?.text = ""
  644. }
  645. }
  646. }