fix(iOS): show recorder errors as full-screen overlay instead of fleeting toast

- Added recorderErrorMessage @Published var for persistent error display
- Recording errors now shown as overlay with error details + Dismiss button
- presentShareSheet now logs errors and sets recorderErrorMessage on failure
- Errors like 'No window scene' or 'No view controller' visible on screen
This commit is contained in:
yumoqing 2026-07-17 21:28:15 +08:00
parent 04fb3acecc
commit f73bc4532e
2 changed files with 42 additions and 8 deletions

View File

@ -440,6 +440,30 @@ struct PlayerContentView: View {
// loading/buffering/error
PlayerStatusOverlay(bridge: bridge)
//
#if os(iOS)
if let errMsg = bridge.recorderErrorMessage {
VStack(spacing: 16) {
Image(systemName: "exclamationmark.triangle.fill")
.font(.system(size: 36))
.foregroundColor(.orange)
Text("Recording Error")
.font(.headline).foregroundColor(.white)
Text(errMsg)
.font(.system(size: 14))
.foregroundColor(.white.opacity(0.8))
.multilineTextAlignment(.center)
.padding(.horizontal, 40)
Button("Dismiss") {
bridge.recorderErrorMessage = nil
}
.buttonStyle(.borderedProminent)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.black.opacity(0.75))
}
#endif
// iOS / macOS
MiniPlayerIcon()
.frame(width: 32, height: 32)

View File

@ -124,6 +124,7 @@ final class PlayerBridge: ObservableObject {
let hlsRecorder = HLSRecorder()
let pipController = PiPController()
@Published var pendingExportURL: URL?
@Published var recorderErrorMessage: String? //
#endif
//
private var diagLogURL: URL?
@ -178,12 +179,14 @@ final class PlayerBridge: ObservableObject {
#if os(iOS)
hlsRecorder.onRecordingSaved = { [weak self] url in
NSLog("[MiniPlayer] onRecordingSaved called: %@", url.lastPathComponent)
NSLog("[MiniPlayer] onRecordingSaved: %@", url.lastPathComponent)
self?.recorderErrorMessage = nil
self?.showToast("Saved: \(url.lastPathComponent)")
// UIKit present SwiftUI sheet binding
self?.presentShareSheet(for: url)
}
hlsRecorder.onError = { [weak self] msg in
NSLog("[MiniPlayer] onError: %@", msg)
self?.recorderErrorMessage = msg
self?.showToast(msg)
}
#endif
@ -192,22 +195,29 @@ final class PlayerBridge: ObservableObject {
#if os(iOS)
/// UIKit present UIActivityViewController SwiftUI sheet sheet
func presentShareSheet(for url: URL) {
NSLog("[MiniPlayer] presentShareSheet: %@", url.lastPathComponent)
guard let windowScene = UIApplication.shared.connectedScenes
.compactMap({ $0 as? UIWindowScene })
.first(where: { $0.activationState == .foregroundActive })
?? UIApplication.shared.connectedScenes.compactMap({ $0 as? UIWindowScene }).first
else { return }
else {
recorderErrorMessage = "No window scene available"
return
}
var topVC = windowScene.keyWindow?.rootViewController
?? windowScene.windows.first(where: { !$0.isHidden && $0.bounds.size != .zero })?.rootViewController
while let presented = topVC?.presentedViewController { topVC = presented }
let activityVC = UIActivityViewController(activityItems: [url], applicationActivities: nil)
activityVC.completionWithItemsHandler = { _, _, _, _ in
//
guard let presenter = topVC else {
recorderErrorMessage = "No view controller to present share sheet"
return
}
topVC?.present(activityVC, animated: true)
NSLog("[MiniPlayer] presentShareSheet: presented for %@", url.lastPathComponent)
let activityVC = UIActivityViewController(activityItems: [url], applicationActivities: nil)
activityVC.completionWithItemsHandler = { _, _, _, _ in }
presenter.present(activityVC, animated: true)
NSLog("[MiniPlayer] presentShareSheet: presented successfully")
}
/// AVAudioSession PiP