fix: tighten iOS main-actor handling
This commit is contained in:
@@ -294,13 +294,14 @@ extension Double {
|
|||||||
// MARK: - Navigation Delegate
|
// MARK: - Navigation Delegate
|
||||||
|
|
||||||
/// Handles navigation policy to intercept clawdis:// deep links from canvas
|
/// Handles navigation policy to intercept clawdis:// deep links from canvas
|
||||||
|
@MainActor
|
||||||
private final class ScreenNavigationDelegate: NSObject, WKNavigationDelegate {
|
private final class ScreenNavigationDelegate: NSObject, WKNavigationDelegate {
|
||||||
weak var controller: ScreenController?
|
weak var controller: ScreenController?
|
||||||
|
|
||||||
func webView(
|
func webView(
|
||||||
_ webView: WKWebView,
|
_ webView: WKWebView,
|
||||||
decidePolicyFor navigationAction: WKNavigationAction,
|
decidePolicyFor navigationAction: WKNavigationAction,
|
||||||
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void)
|
decisionHandler: @escaping @MainActor @Sendable (WKNavigationActionPolicy) -> Void)
|
||||||
{
|
{
|
||||||
guard let url = navigationAction.request.url else {
|
guard let url = navigationAction.request.url else {
|
||||||
decisionHandler(.allow)
|
decisionHandler(.allow)
|
||||||
@@ -310,9 +311,7 @@ private final class ScreenNavigationDelegate: NSObject, WKNavigationDelegate {
|
|||||||
// Intercept clawdis:// deep links
|
// Intercept clawdis:// deep links
|
||||||
if url.scheme == "clawdis" {
|
if url.scheme == "clawdis" {
|
||||||
decisionHandler(.cancel)
|
decisionHandler(.cancel)
|
||||||
Task { @MainActor in
|
self.controller?.onDeepLink?(url)
|
||||||
self.controller?.onDeepLink?(url)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,15 +323,11 @@ private final class ScreenNavigationDelegate: NSObject, WKNavigationDelegate {
|
|||||||
didFailProvisionalNavigation _: WKNavigation?,
|
didFailProvisionalNavigation _: WKNavigation?,
|
||||||
withError error: any Error)
|
withError error: any Error)
|
||||||
{
|
{
|
||||||
Task { @MainActor in
|
self.controller?.errorText = error.localizedDescription
|
||||||
self.controller?.errorText = error.localizedDescription
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func webView(_: WKWebView, didFail _: WKNavigation?, withError error: any Error) {
|
func webView(_: WKWebView, didFail _: WKNavigation?, withError error: any Error) {
|
||||||
Task { @MainActor in
|
self.controller?.errorText = error.localizedDescription
|
||||||
self.controller?.errorText = error.localizedDescription
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ import ReplayKit
|
|||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
final class ScreenRecordService {
|
final class ScreenRecordService {
|
||||||
|
private struct UncheckedSendableBox<T>: @unchecked Sendable {
|
||||||
|
let value: T
|
||||||
|
}
|
||||||
|
|
||||||
enum ScreenRecordError: LocalizedError {
|
enum ScreenRecordError: LocalizedError {
|
||||||
case invalidScreenIndex(Int)
|
case invalidScreenIndex(Int)
|
||||||
case captureFailed(String)
|
case captureFailed(String)
|
||||||
@@ -20,6 +24,7 @@ final class ScreenRecordService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// swiftlint:disable:next cyclomatic_complexity
|
||||||
func record(
|
func record(
|
||||||
screenIndex: Int?,
|
screenIndex: Int?,
|
||||||
durationMs: Int?,
|
durationMs: Int?,
|
||||||
@@ -165,8 +170,10 @@ final class ScreenRecordService {
|
|||||||
videoInput.markAsFinished()
|
videoInput.markAsFinished()
|
||||||
audioInput?.markAsFinished()
|
audioInput?.markAsFinished()
|
||||||
|
|
||||||
|
let writerBox = UncheckedSendableBox(value: writer)
|
||||||
try await withCheckedThrowingContinuation { (cont: CheckedContinuation<Void, Error>) in
|
try await withCheckedThrowingContinuation { (cont: CheckedContinuation<Void, Error>) in
|
||||||
writer.finishWriting {
|
writerBox.value.finishWriting {
|
||||||
|
let writer = writerBox.value
|
||||||
if let err = writer.error {
|
if let err = writer.error {
|
||||||
cont.resume(throwing: ScreenRecordError.writeFailed(err.localizedDescription))
|
cont.resume(throwing: ScreenRecordError.writeFailed(err.localizedDescription))
|
||||||
} else if writer.status != .completed {
|
} else if writer.status != .completed {
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ final class VoiceWakeManager: NSObject {
|
|||||||
|
|
||||||
private var lastDispatched: String?
|
private var lastDispatched: String?
|
||||||
private var onCommand: (@Sendable (String) async -> Void)?
|
private var onCommand: (@Sendable (String) async -> Void)?
|
||||||
private nonisolated(unsafe) var userDefaultsObserver: NSObjectProtocol?
|
private var userDefaultsObserver: NSObjectProtocol?
|
||||||
|
|
||||||
override init() {
|
override init() {
|
||||||
super.init()
|
super.init()
|
||||||
@@ -110,7 +110,7 @@ final class VoiceWakeManager: NSObject {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
@MainActor deinit {
|
||||||
if let userDefaultsObserver = self.userDefaultsObserver {
|
if let userDefaultsObserver = self.userDefaultsObserver {
|
||||||
NotificationCenter.default.removeObserver(userDefaultsObserver)
|
NotificationCenter.default.removeObserver(userDefaultsObserver)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user