fix: save dialog not appearing after recording on macOS/iOS
macOS: - Replace deprecated NSSavePanel.begin(completionHandler:) with async begin() API - The old API has been deprecated since macOS 12 and may silently fail on macOS 26 - Added diagnostic logging throughout recording completion flow iOS: - Added diagnostic logging to track onRecordingSaved → pendingExportURL → sheet chain - Logs file existence, size after recording completes Diagnostic logging added to help verify the save dialog flow: - macOS: file size check, showSaveDialog entry, NSSavePanel response - iOS: recordStream output verification, onRecordingSaved call, sheet binding activation
This commit is contained in:
parent
01bf7d6f4a
commit
04990674cc
@ -36,10 +36,13 @@ final class HLSRecorder: ObservableObject {
|
||||
recordTask = Task {
|
||||
do {
|
||||
let outputURL = try await recordStream(url: url)
|
||||
NSLog("[MiniPlayer] recordStream completed: %@", outputURL.path)
|
||||
NSLog("[MiniPlayer] recordStream completed: %@, exists: %d", outputURL.path, FileManager.default.fileExists(atPath: outputURL.path))
|
||||
let attrs = try? FileManager.default.attributesOfItem(atPath: outputURL.path)
|
||||
NSLog("[MiniPlayer] Output file size: %lld", (attrs?[.size] as? Int64) ?? 0)
|
||||
await MainActor.run {
|
||||
self.isRecording = false
|
||||
self.timer?.invalidate()
|
||||
NSLog("[MiniPlayer] Calling onRecordingSaved...")
|
||||
self.onRecordingSaved?(outputURL)
|
||||
}
|
||||
} catch is CancellationError {
|
||||
|
||||
@ -585,10 +585,15 @@ struct BricksAppView: View {
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: Binding<Bool>(
|
||||
get: { bridge.pendingExportURL != nil },
|
||||
get: {
|
||||
let has = bridge.pendingExportURL != nil
|
||||
if has { NSLog("[MiniPlayer] Sheet binding: pendingExportURL=%@", bridge.pendingExportURL?.lastPathComponent ?? "nil") }
|
||||
return has
|
||||
},
|
||||
set: { if !$0 { bridge.pendingExportURL = nil } }
|
||||
)) {
|
||||
if let url = bridge.pendingExportURL {
|
||||
NSLog("[MiniPlayer] Presenting ActivityShareSheet for: %@", url.lastPathComponent)
|
||||
ActivityShareSheet(url: url) {
|
||||
bridge.pendingExportURL = nil
|
||||
}
|
||||
|
||||
@ -178,8 +178,10 @@ final class PlayerBridge: ObservableObject {
|
||||
|
||||
#if os(iOS)
|
||||
hlsRecorder.onRecordingSaved = { [weak self] url in
|
||||
NSLog("[MiniPlayer] onRecordingSaved called, setting pendingExportURL: %@", url.lastPathComponent)
|
||||
self?.showToast("Saved: \(url.lastPathComponent)")
|
||||
self?.pendingExportURL = url
|
||||
NSLog("[MiniPlayer] pendingExportURL set to: %@", url.lastPathComponent)
|
||||
}
|
||||
hlsRecorder.onError = { [weak self] msg in
|
||||
self?.showToast(msg)
|
||||
|
||||
@ -62,10 +62,13 @@ final class PlayerRecorder: NSObject {
|
||||
try await recorder.start(url: url, outputPath: tempURL.path, duration: 0)
|
||||
// duration=0 表示无限录制,直到 stop() 被调用
|
||||
// start 在 stop() 后会正常返回
|
||||
NSLog("[Recorder] ✓ Recording completed: %@", tempURL.path)
|
||||
NSLog("[Recorder] ✓ Recording completed: %@, file exists: %d", tempURL.path, FileManager.default.fileExists(atPath: tempURL.path))
|
||||
let attrs = try? FileManager.default.attributesOfItem(atPath: tempURL.path)
|
||||
NSLog("[Recorder] Output file size: %lld", (attrs?[.size] as? Int64) ?? 0)
|
||||
await MainActor.run {
|
||||
RecorderState.isFinalizing = false
|
||||
self?.stopDurationTimer()
|
||||
NSLog("[Recorder] Calling showSaveDialog...")
|
||||
self?.showSaveDialog(tempURL: tempURL)
|
||||
}
|
||||
} catch {
|
||||
@ -129,6 +132,7 @@ final class PlayerRecorder: NSObject {
|
||||
// MARK: - 保存对话框
|
||||
|
||||
private func showSaveDialog(tempURL: URL) {
|
||||
NSLog("[Recorder] showSaveDialog called for: %@", tempURL.lastPathComponent)
|
||||
let panel = NSSavePanel()
|
||||
panel.allowedContentTypes = [.mpeg4Movie]
|
||||
// 默认文件名去掉 temp_ 前缀
|
||||
@ -136,25 +140,28 @@ final class PlayerRecorder: NSObject {
|
||||
panel.nameFieldStringValue = defaultName
|
||||
panel.directoryURL = saveDirectory
|
||||
|
||||
panel.begin { [weak self] response in
|
||||
Task { @MainActor in
|
||||
if response == .OK, let url = panel.url {
|
||||
do {
|
||||
if FileManager.default.fileExists(atPath: url.path) {
|
||||
try FileManager.default.removeItem(at: url)
|
||||
}
|
||||
try FileManager.default.moveItem(at: tempURL, to: url)
|
||||
NSLog("[Recorder] ✓ Saved: %@", url.path)
|
||||
self?.onRecordingSaved?(url)
|
||||
} catch {
|
||||
NSLog("[Recorder] ✗ Save failed: %@", error.localizedDescription)
|
||||
self?.onError?("Save failed: \(error.localizedDescription)")
|
||||
// NSSavePanel.begin(completionHandler:) 已被 macOS 12 废弃,macOS 26 上可能静默失效
|
||||
// 使用现代 async begin() API
|
||||
Task { @MainActor [weak self] in
|
||||
NSLog("[Recorder] NSSavePanel.begin() starting...")
|
||||
let response = await panel.begin()
|
||||
NSLog("[Recorder] NSSavePanel response: %d", response.rawValue)
|
||||
if response == .OK, let url = panel.url {
|
||||
do {
|
||||
if FileManager.default.fileExists(atPath: url.path) {
|
||||
try FileManager.default.removeItem(at: url)
|
||||
}
|
||||
} else {
|
||||
try? FileManager.default.removeItem(at: tempURL)
|
||||
try FileManager.default.moveItem(at: tempURL, to: url)
|
||||
NSLog("[Recorder] ✓ Saved: %@", url.path)
|
||||
self?.onRecordingSaved?(url)
|
||||
} catch {
|
||||
NSLog("[Recorder] ✗ Save failed: %@", error.localizedDescription)
|
||||
self?.onError?("Save failed: \(error.localizedDescription)")
|
||||
}
|
||||
self?.checkPendingTerminate()
|
||||
} else {
|
||||
try? FileManager.default.removeItem(at: tempURL)
|
||||
}
|
||||
self?.checkPendingTerminate()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user