Files
iOS/Sources/Extensions/Watch/InterfaceController.swift
Zac West 4d9a530637 Reorganize files in repo, pull out build settings from pbxproj (#1140)
This is somewhat in prep of being able to make the project file generated, but also just organizes things into more concrete directory structures.

This pulls out _all_ of the build settings from the root level, and most from the target level, into xcconfigs.

The new directory structure looks like:

- Sources
  - App
    - (everything from HomeAssistant/)
  - WatchApp
  - Shared
  - MacBridge
  - Extensions
    - Intents
    - NotificationContent
    - NotificationService
    - Share
    - Today
    - Watch
    - Widgets
- Tests
  - App
  - UI
  - Shared

Somewhat intentionally, the file structure under these is not yet standardized/organized.

The project targets are now:

- App
- WatchApp
- Shared-iOS
- Shared-watchOS
- MacBridge
- Tests-App
- Tests-UI
- Tests-Shared
- Extension-Intents
- Extension-NotificationContent
- Extension-NotificationService
- Extension-Share
- Extension-Today
- Extension-Widget
- WatchExtension-Watch

This does not yet clean up resources vs. sources, nor does it handle some of the "it's in Sources/App but it's part of Shared" crossover directory issues.
2020-10-03 00:15:04 -07:00

171 lines
6.1 KiB
Swift

//
// InterfaceController.swift
// WatchApp Extension
//
// Created by Robert Trencheny on 9/24/18.
// Copyright © 2018 Robbie Trencheny. All rights reserved.
//
import Foundation
import WatchKit
import EMTLoadingIndicator
import RealmSwift
import Communicator
import Shared
class InterfaceController: WKInterfaceController {
@IBOutlet weak var tableView: WKInterfaceTable!
@IBOutlet weak var noActionsLabel: WKInterfaceLabel!
var notificationToken: NotificationToken?
var actions: Results<Action>?
override func awake(withContext context: Any?) {
super.awake(withContext: context)
Iconic.registerMaterialDesignIcons()
self.setupTable()
}
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
}
override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
}
func setupTable() {
let realm = Realm.live()
self.noActionsLabel.setText(L10n.Watch.Labels.noAction)
let actions = realm.objects(Action.self).sorted(byKeyPath: "Position")
self.actions = actions
notificationToken = actions.observe { (changes: RealmCollectionChange) in
guard let tableView = self.tableView else { return }
self.noActionsLabel.setHidden(actions.count > 0)
switch changes {
case .initial:
// Results are now populated and can be accessed without blocking the UI
self.tableView.setNumberOfRows(actions.count, withRowType: "actionRowType")
for idx in actions.indices {
self.setupRow(idx)
}
case .update(_, let deletions, let insertions, let modifications):
let insertionsSet = NSMutableIndexSet()
insertions.forEach(insertionsSet.add)
tableView.insertRows(at: IndexSet(insertionsSet), withRowType: "actionRowType")
insertions.forEach(self.setupRow)
let deletionsSet = NSMutableIndexSet()
deletions.forEach(deletionsSet.add)
tableView.removeRows(at: IndexSet(deletionsSet))
modifications.forEach(self.setupRow)
case .error(let error):
// An error occurred while opening the Realm file on the background worker thread
Current.Log.error("Error during Realm notifications! \(error)")
}
}
}
func setupRow(_ index: Int) {
DispatchQueue.main.async {
guard let row = self.tableView.rowController(at: index) as? ActionRowType,
let action = self.actions?[index] else { return }
Current.Log.verbose("Setup row \(index) with action \(action)")
row.group.setBackgroundColor(UIColor(hex: action.BackgroundColor))
row.indicator = EMTLoadingIndicator(interfaceController: self, interfaceImage: row.image,
width: 24, height: 24, style: .dot)
row.icon = MaterialDesignIcons.init(named: action.IconName)
let iconColor = UIColor(hex: action.IconColor)
row.image.setImage(row.icon.image(ofSize: CGSize(width: 24, height: 24), color: iconColor))
row.image.setAlpha(1)
row.label.setText(action.Text)
row.label.setTextColor(UIColor(hex: action.TextColor))
}
}
override func table(_ table: WKInterfaceTable, didSelectRowAt rowIndex: Int) {
let selectedAction = self.actions![rowIndex]
Current.Log.verbose("Selected action row at index \(rowIndex), \(selectedAction)")
guard let row = self.tableView.rowController(at: rowIndex) as? ActionRowType else {
Current.Log.warning("Row at \(rowIndex) is not ActionRowType")
return
}
row.indicator?.prepareImagesForWait()
row.indicator?.showWait()
if Communicator.shared.currentReachability == .immediateMessaging {
Current.Log.verbose("Signaling action pressed via phone")
let actionMessage = ImmediateMessage(identifier: "ActionRowPressed",
content: ["ActionID": selectedAction.ID],
replyHandler: { replyDict in
Current.Log.verbose("Received reply dictionary \(replyDict)")
self.handleActionSuccess(row, rowIndex)
}, errorHandler: { err in
Current.Log.error("Received error when sending immediate message \(err)")
self.handleActionFailure(row, rowIndex)
})
Current.Log.verbose("Sending ActionRowPressed message \(actionMessage)")
do {
try Communicator.shared.send(immediateMessage: actionMessage)
self.handleActionSuccess(row, rowIndex)
} catch let error {
Current.Log.error("Action notification send failed: \(error)")
self.handleActionFailure(row, rowIndex)
}
} else { // Phone isn't connected
Current.Log.verbose("Signaling action pressed via watch")
HomeAssistantAPI.authenticatedAPIPromise.then { api in
api.HandleAction(actionID: selectedAction.ID, source: .Watch)
}.done { _ in
self.handleActionSuccess(row, rowIndex)
}.catch { err -> Void in
Current.Log.error("Error during action event fire: \(err)")
self.handleActionFailure(row, rowIndex)
}
}
}
func handleActionSuccess(_ row: ActionRowType, _ index: Int) {
WKInterfaceDevice.current().play(.success)
row.image.stopAnimating()
self.setupRow(index)
}
func handleActionFailure(_ row: ActionRowType, _ index: Int) {
WKInterfaceDevice.current().play(.failure)
row.image.stopAnimating()
self.setupRow(index)
}
deinit {
notificationToken?.invalidate()
}
}