Skip to content

Commit

Permalink
Update implementation to align with frontend
Browse files Browse the repository at this point in the history
  • Loading branch information
bgoncal committed Feb 12, 2024
1 parent cc40070 commit 8a7169b
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 86 deletions.
4 changes: 4 additions & 0 deletions HomeAssistant.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,7 @@
42266B1D2B741FB400E94A71 /* BarcodeScannerCameraView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42266B172B741FB300E94A71 /* BarcodeScannerCameraView.swift */; };
42266B1F2B741FB400E94A71 /* BarcodeScannerDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42266B192B741FB300E94A71 /* BarcodeScannerDataModel.swift */; };
42266B202B741FB400E94A71 /* BarcodeScannerCamera.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42266B1A2B741FB400E94A71 /* BarcodeScannerCamera.swift */; };
42266B252B7A4BA900E94A71 /* BarcodeScannerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42266B242B7A4BA900E94A71 /* BarcodeScannerViewModel.swift */; };
424A7F462B188946008C8DF3 /* WidgetBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = 424A7F452B188946008C8DF3 /* WidgetBackground.swift */; };
424A7F482B188BF3008C8DF3 /* WidgetContentMargin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 424A7F472B188BF3008C8DF3 /* WidgetContentMargin.swift */; };
424DD05A2B3509170057E456 /* CarPlayActionsTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 424DD0592B3509170057E456 /* CarPlayActionsTemplate.swift */; };
Expand Down Expand Up @@ -1577,6 +1578,7 @@
42266B172B741FB300E94A71 /* BarcodeScannerCameraView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BarcodeScannerCameraView.swift; sourceTree = "<group>"; };
42266B192B741FB300E94A71 /* BarcodeScannerDataModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BarcodeScannerDataModel.swift; sourceTree = "<group>"; };
42266B1A2B741FB400E94A71 /* BarcodeScannerCamera.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BarcodeScannerCamera.swift; sourceTree = "<group>"; };
42266B242B7A4BA900E94A71 /* BarcodeScannerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BarcodeScannerViewModel.swift; sourceTree = "<group>"; };
4242A2B12B2B5C8000E9F001 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = en; path = en.lproj/AppIntentVocabulary.plist; sourceTree = "<group>"; };
4242A2B22B2B5C8100E9F001 /* ca-ES */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "ca-ES"; path = "ca-ES.lproj/AppIntentVocabulary.plist"; sourceTree = "<group>"; };
4242A2B32B2B5C8100E9F001 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "zh-Hans"; path = "zh-Hans.lproj/AppIntentVocabulary.plist"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3065,6 +3067,7 @@
children = (
42266B152B741F9F00E94A71 /* Camera */,
42266B102B740E4C00E94A71 /* BarcodeScannerView.swift */,
42266B242B7A4BA900E94A71 /* BarcodeScannerViewModel.swift */,
);
path = QRCodeScanner;
sourceTree = "<group>";
Expand Down Expand Up @@ -5642,6 +5645,7 @@
425573CC2B5574AD00145217 /* CarPlayAreasZonesTemplate+Build.swift in Sources */,
B626AAF11D8F972800A0D225 /* SettingsDetailViewController.swift in Sources */,
1127381C2622B6F300F5E312 /* DebugSettingsViewController.swift in Sources */,
42266B252B7A4BA900E94A71 /* BarcodeScannerViewModel.swift in Sources */,
11DE823024FAE66F00E636B8 /* UIWindow+Additions.swift in Sources */,
11DA6B4F2713912F008ADFAF /* OnboardingPermissionViewController.swift in Sources */,
42CA28BB2B1028330093B31A /* SimulatorThreadClientService.swift in Sources */,
Expand Down
24 changes: 8 additions & 16 deletions Sources/App/QRCodeScanner/BarcodeScannerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,9 @@ import CodeScanner
import Shared
import SwiftUI

enum QRScannerResult {
case cancelled
case alternativeOption
case success(_ code: String, _ format: String)
}

struct BarcodeScannerView: View {
@Environment(\.dismiss) private var dismiss
@StateObject private var viewModel: BarcodeScannerViewModel
// Use single data model so both camera previews use same camera stream
@State private var cameraDataModel = BarcodeScannerDataModel()
private let cameraSquareSize: CGFloat = 320
Expand All @@ -21,18 +16,17 @@ struct BarcodeScannerView: View {
private let title: String
private let description: String
private let alternativeOptionLabel: String?
private let completion: (QRScannerResult) -> Void

init(
title: String,
description: String,
alternativeOptionLabel: String? = nil,
completion: @escaping (QRScannerResult) -> Void
incomingMessageId: Int
) {
self.title = title
self.description = description
self.alternativeOptionLabel = alternativeOptionLabel
self.completion = completion
self._viewModel = .init(wrappedValue: .init(incomingMessageId: incomingMessageId))
}

var body: some View {
Expand All @@ -49,16 +43,15 @@ struct BarcodeScannerView: View {
}
.onAppear {
cameraDataModel.camera.qrFound = { code, format in
self.completion(.success(code, format))
self.dismiss()
viewModel.scannedCode(code, format: format)
}
}
}

private var topInformation: some View {
VStack(spacing: 8) {
Button(action: {
completion(.cancelled)
viewModel.aborted(.canceled)
dismiss()
}, label: {
Image(systemName: "xmark")
Expand All @@ -78,8 +71,7 @@ struct BarcodeScannerView: View {

if let alternativeOptionLabel {
Button {
completion(.alternativeOption)
dismiss()
viewModel.aborted(.alternativeOptions)
} label: {
Text(alternativeOptionLabel)
.font(.subheadline)
Expand Down Expand Up @@ -134,10 +126,10 @@ struct BarcodeScannerView: View {
}

#Preview {
BarcodeScannerView(title: "Scan QR-code", description: "Find the code on your device", completion: { _ in })
BarcodeScannerView(title: "Scan QR-code", description: "Find the code on your device", incomingMessageId: 1)
}

class BarcodeScannerHostingController: UIHostingController<BarcodeScannerView> {
final class BarcodeScannerHostingController: UIHostingController<BarcodeScannerView> {
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
[.portrait]
}
Expand Down
45 changes: 45 additions & 0 deletions Sources/App/QRCodeScanner/BarcodeScannerViewModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import Foundation
import Shared

final class BarcodeScannerViewModel: ObservableObject {
enum AbortReason: String {
case canceled
case alternativeOptions = "alternative_options"
}

private let incomingMessageId: Int

init(incomingMessageId: Int) {
self.incomingMessageId = incomingMessageId
}

func scannedCode(_ code: String, format: String) {
Current.sceneManager.webViewWindowControllerPromise.then(\.webViewControllerPromise)
.done { [weak self] controller in
guard let incomingMessageId = self?.incomingMessageId else { return }
controller
.sendExternalBus(message: .init(
id: incomingMessageId,
command: WebViewExternalBusOutgoingMessage.barCodeScanResult.rawValue,
payload: [
"rawValue": code,
"format": format,
]
))
}
}

func aborted(_ reason: AbortReason) {
Current.sceneManager.webViewWindowControllerPromise.then(\.webViewControllerPromise)
.done { [weak self] controller in
guard let incomingMessageId = self?.incomingMessageId else { return }
controller.sendExternalBus(message: .init(
id: incomingMessageId,
command: WebViewExternalBusOutgoingMessage.barCodeScanAborted.rawValue,
payload: [
"reason": reason.rawValue,
]
))
}
}
}
14 changes: 12 additions & 2 deletions Sources/App/WebView/Tests/WebViewExternalBusMessageTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,18 @@ final class WebViewExternalBusMessageTests: XCTestCase {
XCTAssertEqual(WebViewExternalBusMessage.themeUpdate.rawValue, "theme-update")
XCTAssertEqual(WebViewExternalBusMessage.matterCommission.rawValue, "matter/commission")
XCTAssertEqual(WebViewExternalBusMessage.threadImportCredentials.rawValue, "thread/import_credentials")
XCTAssertEqual(WebViewExternalBusMessage.qrCodeScanner.rawValue, "barcode/scan")
XCTAssertEqual(WebViewExternalBusMessage.barCodeScanner.rawValue, "bar_code/scan")
XCTAssertEqual(WebViewExternalBusMessage.barCodeScannerClose.rawValue, "bar_code/close")
XCTAssertEqual(WebViewExternalBusMessage.barCodeScannerNotify.rawValue, "bar_code/notify")

XCTAssertEqual(WebViewExternalBusMessage.allCases.count, 10)
XCTAssertEqual(WebViewExternalBusMessage.allCases.count, 12)
}

func test_externalBus_outgoing_messageKeys() {
XCTAssertEqual(WebViewExternalBusOutgoingMessage.showAutomationEditor.rawValue, "automation/editor/show")
XCTAssertEqual(WebViewExternalBusOutgoingMessage.barCodeScanResult.rawValue, "bar_code/scan_result")
XCTAssertEqual(WebViewExternalBusOutgoingMessage.barCodeScanAborted.rawValue, "bar_code/aborted")

XCTAssertEqual(WebViewExternalBusOutgoingMessage.allCases.count, 3)
}
}
104 changes: 39 additions & 65 deletions Sources/App/WebView/WebViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ final class WebViewController: UIViewController, WKNavigationDelegate, WKUIDeleg

private var keepAliveTimer: Timer?
private var initialURL: URL?
private var barCodeScannerController: UIViewController?

private let settingsButton: UIButton! = {
let button = UIButton()
Expand Down Expand Up @@ -839,19 +840,22 @@ final class WebViewController: UIViewController, WKNavigationDelegate, WKUIDeleg
showActionAutomationEditorNotAvailable()
return
}
sendExternalBus(message: .init(command: "automation/editor/show", payload: [
"config": [
"trigger": [
[
"platform": "event",
"event_type": "ios.action_fired",
"event_data": [
"actionID": actionId,
sendExternalBus(message: .init(
command: WebViewExternalBusOutgoingMessage.showAutomationEditor.rawValue,
payload: [
"config": [
"trigger": [
[
"platform": "event",
"event_type": "ios.action_fired",
"event_data": [
"actionID": actionId,
],
],
],
],
],
]))
]
))
}

private func showActionAutomationEditorNotAvailable() {
Expand Down Expand Up @@ -1062,19 +1066,24 @@ extension WebViewController: WKScriptMessageHandler {
}
case .threadImportCredentials:
threadCredentialsRequested()
case .qrCodeScanner:
response = Guarantee { seal in
guard let title = incomingMessage.Payload?["title"] as? String,
let description = incomingMessage.Payload?["description"] as? String,
let incomingMessageId = incomingMessage.ID else { return }
qrCodeScannerRequested(
title: title,
description: description,
alternativeOptionLabel: incomingMessage.Payload?["alternative_option_label"] as? String,
incomingMessageId: incomingMessageId,
seal: seal
)
}
case .barCodeScanner:
guard let title = incomingMessage.Payload?["title"] as? String,
let description = incomingMessage.Payload?["description"] as? String,
let incomingMessageId = incomingMessage.ID else { return }
qrCodeScannerRequested(
title: title,
description: description,
alternativeOptionLabel: incomingMessage.Payload?["alternative_option_label"] as? String,
incomingMessageId: incomingMessageId
)
case .barCodeScannerClose:
barCodeScannerController?.dismiss(animated: true)
case .barCodeScannerNotify:
guard let message = incomingMessage.Payload?["message"] as? String else { return }
let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
alert.addAction(.init(title: L10n.okLabel, style: .default))
let controller = barCodeScannerController ?? self
controller.present(alert, animated: false, completion: nil)
}
} else {
Current.Log.error("unknown: \(incomingMessage.MessageType)")
Expand All @@ -1086,7 +1095,7 @@ extension WebViewController: WKScriptMessageHandler {
}

@discardableResult
private func sendExternalBus(message: WebSocketMessage) -> Promise<Void> {
public func sendExternalBus(message: WebSocketMessage) -> Promise<Void> {
Promise<Void> { seal in
DispatchQueue.main.async { [self] in
do {
Expand Down Expand Up @@ -1125,52 +1134,17 @@ extension WebViewController: WKScriptMessageHandler {
title: String,
description: String,
alternativeOptionLabel: String?,
incomingMessageId: Int,
seal: @escaping (WebSocketMessage) -> Void
incomingMessageId: Int
) {
let qrCodeScannerView = BarcodeScannerHostingController(rootView: BarcodeScannerView(
barCodeScannerController = BarcodeScannerHostingController(rootView: BarcodeScannerView(
title: title,
description: description,
alternativeOptionLabel: alternativeOptionLabel,
completion: { result in
switch result {
case .cancelled:
seal(
WebSocketMessage(
id: incomingMessageId,
type: "result",
result: [
"action": "canceled",
]
)
)
case .alternativeOption:
seal(
WebSocketMessage(
id: incomingMessageId,
type: "result",
result: [
"action": "alternative_options",
]
)
)
case let .success(code, format):
seal(
WebSocketMessage(
id: incomingMessageId,
type: "result",
result: [
"action": "scan_result",
"result": code,
"format": format,
]
)
)
}
}
incomingMessageId: incomingMessageId
))
qrCodeScannerView.modalPresentationStyle = .fullScreen
present(qrCodeScannerView, animated: true)
barCodeScannerController?.modalPresentationStyle = .fullScreen
guard let barCodeScannerController else { return }
present(barCodeScannerController, animated: true)
}
}

Expand Down
10 changes: 9 additions & 1 deletion Sources/App/WebView/WebViewExternalBusMessage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,13 @@ enum WebViewExternalBusMessage: String, CaseIterable {
case themeUpdate = "theme-update"
case matterCommission = "matter/commission"
case threadImportCredentials = "thread/import_credentials"
case qrCodeScanner = "barcode/scan"
case barCodeScanner = "bar_code/scan"
case barCodeScannerClose = "bar_code/close"
case barCodeScannerNotify = "bar_code/notify"
}

enum WebViewExternalBusOutgoingMessage: String, CaseIterable {
case showAutomationEditor = "automation/editor/show"
case barCodeScanResult = "bar_code/scan_result"
case barCodeScanAborted = "bar_code/aborted"
}
4 changes: 2 additions & 2 deletions Sources/Shared/API/WebSocket/WebSocketMessage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ public class WebSocketMessage: Codable {
self.command = nil
}

public init(command: String, payload: [String: Any]? = nil) {
self.ID = -1
public init(id: Int = -1, command: String, payload: [String: Any]? = nil) {
self.ID = id
self.MessageType = "command"
self.command = command
self.Payload = payload
Expand Down

0 comments on commit 8a7169b

Please sign in to comment.