From 0f234251c3ece17fd80345c8bd520b0fc1b3fcfb Mon Sep 17 00:00:00 2001 From: lihaoyun6 Date: Mon, 20 May 2024 04:31:34 +0800 Subject: [PATCH] fix camera overlayer; fix Presenter Overlay not working --- QuickRecorder.xcodeproj/project.pbxproj | 8 ++--- QuickRecorder/AVContext.swift | 2 +- QuickRecorder/QuickRecorderApp.swift | 16 ++++----- QuickRecorder/RecordEngine.swift | 1 + QuickRecorder/SCContext.swift | 35 +++++++++++-------- QuickRecorder/ViewModel/AppSelector.swift | 2 +- QuickRecorder/ViewModel/AreaSelector.swift | 2 +- QuickRecorder/ViewModel/CameraOverlayer.swift | 13 ++++--- QuickRecorder/ViewModel/ContentView.swift | 4 +-- QuickRecorder/ViewModel/ScreenSelector.swift | 2 +- QuickRecorder/ViewModel/StatusBar.swift | 2 +- QuickRecorder/ViewModel/WinSelector.swift | 2 +- .../zh-Hans.lproj/Localizable.strings | 6 ++-- 13 files changed, 52 insertions(+), 43 deletions(-) diff --git a/QuickRecorder.xcodeproj/project.pbxproj b/QuickRecorder.xcodeproj/project.pbxproj index 5c13257..587abe9 100644 --- a/QuickRecorder.xcodeproj/project.pbxproj +++ b/QuickRecorder.xcodeproj/project.pbxproj @@ -409,7 +409,7 @@ CODE_SIGN_ENTITLEMENTS = QuickRecorder/QuickRecorder.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 123; + CURRENT_PROJECT_VERSION = 124; DEVELOPMENT_ASSET_PATHS = "\"QuickRecorder/Preview Content\""; DEVELOPMENT_TEAM = L4T783637F; ENABLE_HARDENED_RUNTIME = YES; @@ -425,7 +425,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.3; - MARKETING_VERSION = 1.2.3; + MARKETING_VERSION = 1.2.4; PRODUCT_BUNDLE_IDENTIFIER = com.lihaoyun6.QuickRecorder; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -441,7 +441,7 @@ CODE_SIGN_ENTITLEMENTS = QuickRecorder/QuickRecorder.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 123; + CURRENT_PROJECT_VERSION = 124; DEVELOPMENT_ASSET_PATHS = "\"QuickRecorder/Preview Content\""; DEVELOPMENT_TEAM = L4T783637F; ENABLE_HARDENED_RUNTIME = YES; @@ -457,7 +457,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.3; - MARKETING_VERSION = 1.2.3; + MARKETING_VERSION = 1.2.4; PRODUCT_BUNDLE_IDENTIFIER = com.lihaoyun6.QuickRecorder; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; diff --git a/QuickRecorder/AVContext.swift b/QuickRecorder/AVContext.swift index e4fa7d2..5c6835c 100644 --- a/QuickRecorder/AVContext.swift +++ b/QuickRecorder/AVContext.swift @@ -109,7 +109,7 @@ class AVOutputClass: NSObject, AVCaptureFileOutputRecordingDelegate, AVCaptureVi SCContext.previewSession.startRunning() DispatchQueue.main.async { - AppDelegate.shared.closeAllWindow() + AppDelegate.shared.closeAllWindow("Area Overlayer".local) AppDelegate.shared.updateStatusBar() AppDelegate.shared.startDeviceOverlayer(size: NSSize(width: 300, height: 500)) } diff --git a/QuickRecorder/QuickRecorderApp.swift b/QuickRecorder/QuickRecorderApp.swift index 58afb83..3945bf0 100644 --- a/QuickRecorder/QuickRecorderApp.swift +++ b/QuickRecorder/QuickRecorderApp.swift @@ -102,7 +102,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, SCStreamDelegate, SCStreamOu var filter: SCContentFilter? var isCameraReady = false var isPresenterON = false - var presenterType = "no" + var presenterType = "OFF" //var lastTime = CMTime(value: 0, timescale: 600) func mousePointerReLocation(event: NSEvent) { @@ -189,8 +189,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, SCStreamDelegate, SCStreamOu "recordWinSound": true, "trimAfterRecord": false, "showOnDock": true, - "showMenubar": false, - "macOS1274Alert": true + "showMenubar": false ] ) @@ -201,15 +200,12 @@ class AppDelegate: NSObject, NSApplicationDelegate, SCStreamDelegate, SCStreamOu SCContext.updateAvailableContent{ print("available content has been updated") let os = ProcessInfo.processInfo.operatingSystemVersion - if "\(os.majorVersion).\(os.minorVersion).\(os.patchVersion)" == "12.7.4" && ud.bool(forKey: "macOS1274Alert") { + if "\(os.majorVersion).\(os.minorVersion).\(os.patchVersion)" == "12.7.4" { DispatchQueue.main.async { - let alert = AppDelegate.shared.createAlert( + _ = AppDelegate.shared.createAlert( title: "Compatibility Warning".local, - message: "You are using macOS 12.7.4 QuickRecorder will randomly fail to save recordings in this version!".local, - button1: "OK".local, button2: "Don't remind me again".local) - if alert.runModal() == .alertSecondButtonReturn { - ud.set(false, forKey: "macOS1274Alert") - } + message: "You are using macOS 12.7.4\nOutput files will be randomly corrupted on this version of macOS!\n\nPlease upgrade to 12.7.5 to solve it.".local, + button1: "OK".local).runModal() } } } diff --git a/QuickRecorder/RecordEngine.swift b/QuickRecorder/RecordEngine.swift index 1f70276..48eff8d 100644 --- a/QuickRecorder/RecordEngine.swift +++ b/QuickRecorder/RecordEngine.swift @@ -281,6 +281,7 @@ extension AppDelegate { func outputVideoEffectDidStop(for stream: SCStream) { print("[Presenter Overlay OFF]") + presenterType = "OFF" isPresenterON = false isCameraReady = false DispatchQueue.main.async { diff --git a/QuickRecorder/SCContext.swift b/QuickRecorder/SCContext.swift index 4079ca4..b1407b3 100644 --- a/QuickRecorder/SCContext.swift +++ b/QuickRecorder/SCContext.swift @@ -286,6 +286,7 @@ class SCContext { //statusBarItem.isVisible = false autoStop = 0 recordCam = "" + recordDevice = "" mousePointer.orderOut(nil) screenMagnifier.orderOut(nil) AppDelegate.shared.stopGlobalMouseMonitor() @@ -305,22 +306,26 @@ class SCContext { audioEngine.stop() } vW.finishWriting { - if vW.status != .completed { print("Video writing failed with status: \(vW.status), error: \(String(describing: vW.error))") } startTime = nil - if ud.bool(forKey: "recordMic") && ud.bool(forKey: "recordWinSound") && ud.bool(forKey: "remuxAudio") { - mixAudioTracks(videoURL: URL(fileURLWithPath: filePath)) { result in - switch result { - case .success(let url): - print("Exported video to \(String(describing: url.path))") - showNotification(title: "Recording Completed".local, body: String(format: "File saved to: %@".local, url.path), id: "quickrecorder.completed.\(Date.now)") - if ud.bool(forKey: "trimAfterRecord") { - DispatchQueue.main.async { - let fileURL = URL(fileURLWithPath: filePath).deletingPathExtension() - AppDelegate.shared.createNewWindow(view: VideoTrimmerView(videoURL: fileURL), title: fileURL.lastPathComponent) + if vW.status != .completed { + print("Video writing failed with status: \(vW.status), error: \(String(describing: vW.error))") + showNotification(title: "Failed to save file".local, body: "\(String(describing: vW.error?.localizedDescription))", id: "quickrecorder.error.\(Date.now)") + } else { + if ud.bool(forKey: "recordMic") && ud.bool(forKey: "recordWinSound") && ud.bool(forKey: "remuxAudio") { + mixAudioTracks(videoURL: URL(fileURLWithPath: filePath)) { result in + switch result { + case .success(let url): + print("Exported video to \(String(describing: url.path))") + showNotification(title: "Recording Completed".local, body: String(format: "File saved to: %@".local, url.path), id: "quickrecorder.completed.\(Date.now)") + if ud.bool(forKey: "trimAfterRecord") { + DispatchQueue.main.async { + let fileURL = URL(fileURLWithPath: filePath).deletingPathExtension() + AppDelegate.shared.createNewWindow(view: VideoTrimmerView(videoURL: fileURL), title: fileURL.lastPathComponent) + } } + case .failure(let error): + print("Failed to export video: \(error.localizedDescription)") } - case .failure(let error): - print("Failed to export video: \(error.localizedDescription)") } } } @@ -347,10 +352,10 @@ class SCContext { window = nil screen = nil startTime = nil - + AppDelegate.shared.presenterType = "OFF" AppDelegate.shared.updateStatusBar() - if !(ud.bool(forKey: "recordMic") && ud.bool(forKey: "recordWinSound") && ud.bool(forKey: "remuxAudio")) { + if !(ud.bool(forKey: "recordMic") && ud.bool(forKey: "recordWinSound") && ud.bool(forKey: "remuxAudio")) && vW.status == .completed { let title = "Recording Completed".local var body = String(format: "File saved to folder: %@".local, ud.string(forKey: "saveDirectory")!) if let filePath = filePath { body = String(format: "File saved to: %@".local, filePath) } diff --git a/QuickRecorder/ViewModel/AppSelector.swift b/QuickRecorder/ViewModel/AppSelector.swift index e9d22df..d14830c 100644 --- a/QuickRecorder/ViewModel/AppSelector.swift +++ b/QuickRecorder/ViewModel/AppSelector.swift @@ -198,7 +198,7 @@ struct AppSelector: View { } }.needScale() } - } + }.padding(.leading, 18) Spacer() Button(action: { isPopoverShowing = true diff --git a/QuickRecorder/ViewModel/AreaSelector.swift b/QuickRecorder/ViewModel/AreaSelector.swift index 8af06ba..46c27a8 100644 --- a/QuickRecorder/ViewModel/AreaSelector.swift +++ b/QuickRecorder/ViewModel/AreaSelector.swift @@ -139,7 +139,7 @@ struct AreaSelector: View { } }.needScale() } - } + }.padding(.leading, 18) Spacer() Button(action: { isPopoverShowing = true diff --git a/QuickRecorder/ViewModel/CameraOverlayer.swift b/QuickRecorder/ViewModel/CameraOverlayer.swift index 1856e25..1002845 100644 --- a/QuickRecorder/ViewModel/CameraOverlayer.swift +++ b/QuickRecorder/ViewModel/CameraOverlayer.swift @@ -117,10 +117,12 @@ struct SwiftCameraView: View { }).buttonStyle(.plain).padding(10) }.frame(width: geometry.size.width, height: geometry.size.height) if SCContext.streamType == .window { - Text("Unable to use this overlayer when recording a single window, please use \"Presenter Overlay\"") - .padding() - .colorInvert() - .background(.secondary) + Text("Unable to use camera overlayer when recording a single window!".local + + (isMacOS14 ? " Please use \"Presenter Overlay\"".local : "") + ) + .padding() + .colorInvert() + .background(.secondary) } } } @@ -130,6 +132,7 @@ struct SwiftCameraView: View { struct CameraPopoverView: View { + var closePopover: () -> Void @State private var cameras = SCContext.getCameras() @State private var devices = SCContext.getiDevice() @State private var hoverIndex = -1 @@ -155,6 +158,7 @@ struct CameraPopoverView: View { } ForEach(cameras.indices, id: \.self) { index in Button(action: { + closePopover() if SCContext.recordCam == cameras[index].localizedName { SCContext.recordCam = "" appDelegate.closeCamera() @@ -193,6 +197,7 @@ struct CameraPopoverView: View { if !devices.isEmpty { Divider().padding([.top, .bottom], 4) } ForEach(devices.indices, id: \.self) { index in Button(action: { + closePopover() if SCContext.recordDevice == devices[index].localizedName { SCContext.recordDevice = "" AVOutputClass.shared.closePreview() diff --git a/QuickRecorder/ViewModel/ContentView.swift b/QuickRecorder/ViewModel/ContentView.swift index f338a46..c48664a 100644 --- a/QuickRecorder/ViewModel/ContentView.swift +++ b/QuickRecorder/ViewModel/ContentView.swift @@ -92,7 +92,7 @@ struct ContentView: View { SelectorView(title: "Mobile Device".local, symbol: "apps.ipad") .cornerRadius(8) }).buttonStyle(.plain) - .popover(isPresented: $isPopoverShowing, arrowEdge: .bottom, content: { iDevicePopoverView(closePopover: { isPopoverShowing = false })}) + .popover(isPresented: $isPopoverShowing, arrowEdge: .bottom) { iDevicePopoverView(closePopover: { isPopoverShowing = false })} Divider().frame(height: 70) Button(action: { if fromStatusBar { @@ -182,7 +182,7 @@ extension AppDelegate { func closeMainWindow() { for w in NSApplication.shared.windows.filter({ $0.title == "QuickRecorder".local }) { w.close() } } - func closeAllWindow() { for w in NSApp.windows.filter({ $0.title != "Item-0" && $0.title != "" && $0.title != "Recording Controller".local }) { w.close() } } + func closeAllWindow(_ title: String = "") { for w in NSApp.windows.filter({ $0.title != "Item-0" && $0.title != "" && $0.title != title }) { w.close() }} func showAreaSelector() { guard let scDisplay = SCContext.getSCDisplayWithMouse() else { return } diff --git a/QuickRecorder/ViewModel/ScreenSelector.swift b/QuickRecorder/ViewModel/ScreenSelector.swift index 17d76e9..b1f0c4f 100644 --- a/QuickRecorder/ViewModel/ScreenSelector.swift +++ b/QuickRecorder/ViewModel/ScreenSelector.swift @@ -190,7 +190,7 @@ struct ScreenSelector: View { } }.needScale() } - } + }.padding(.leading, 18) Spacer() Button(action: { isPopoverShowing = true diff --git a/QuickRecorder/ViewModel/StatusBar.swift b/QuickRecorder/ViewModel/StatusBar.swift index 67a1ac5..0283648 100644 --- a/QuickRecorder/ViewModel/StatusBar.swift +++ b/QuickRecorder/ViewModel/StatusBar.swift @@ -89,7 +89,7 @@ struct StatusBarItem: View { }.frame(width: 36).padding([.leading,.trailing], 4) }) .buttonStyle(.plain) - .popover(isPresented: $isPopoverShowing, arrowEdge: .bottom) { CameraPopoverView() } + .popover(isPresented: $isPopoverShowing, arrowEdge: .bottom) { CameraPopoverView(closePopover: { isPopoverShowing = false })} } else { Button(action:{ DispatchQueue.main.async { diff --git a/QuickRecorder/ViewModel/WinSelector.swift b/QuickRecorder/ViewModel/WinSelector.swift index 9024eae..c5e8ac3 100644 --- a/QuickRecorder/ViewModel/WinSelector.swift +++ b/QuickRecorder/ViewModel/WinSelector.swift @@ -227,7 +227,7 @@ struct WinSelector: View { } }.needScale() } - } + }.padding(.leading, 18) Spacer() Button(action: { isPopoverShowing = true diff --git a/QuickRecorder/zh-Hans.lproj/Localizable.strings b/QuickRecorder/zh-Hans.lproj/Localizable.strings index 93bb75a..608c903 100644 --- a/QuickRecorder/zh-Hans.lproj/Localizable.strings +++ b/QuickRecorder/zh-Hans.lproj/Localizable.strings @@ -19,7 +19,7 @@ "Select Applications" = "选择应用程序"; "Permission Required" = "需要授权"; "Compatibility Warning" = "兼容性警告"; -"You are using macOS 12.7.4 QuickRecorder will randomly fail to save recordings in this version!" = "检测到当前系统版本为 macOS 12.7.4\nQuickRecorder 在此版本中会随机出现录像文件保存失败的情况!"; +"You are using macOS 12.7.4\nOutput files will be randomly corrupted on this version of macOS!\n\nPlease upgrade to 12.7.5 to solve it." = "检测到当前系统版本为 macOS 12.7.4\nQuickRecorder 在当前系统版本中会\n随机出现录像文件保存失败的情况!\n\n请升级至 macOS 12.7.5 以解决此问题."; "QuickRecorder needs screen recording permissions, even if you only intend on recording audio." = "QuickRecorder 需要获取录屏权限\n(即使只是用来录制音频)"; "QuickRecorder needs permission to record your microphone." = "QuickRecorder 需要获取麦克风权限来录制所需的声音"; "Please select a folder to save output files" = "请选择录音/录屏文件的保存位置"; @@ -116,7 +116,8 @@ //"Can only be turned off on macOS 14.2 or later!" = "此选项仅 macOS 14.2 或更高版本系统可中可被关闭!"; "Presenter Overlay Delay" = "演讲者前置延迟"; "Open video trimmer after recording" = "录制结束自动打开修剪器"; -"Unable to use camera overlayer when recording a single window, please use \"Presenter Overlay\"" = "单窗口录制模式下无法叠加摄像头画面, 请使用\"演讲者前置\"功能"; +"Unable to use camera overlayer when recording a single window!" = "录制单个窗口时无法使用摄像头浮窗!"; +" Please use \"Presenter Overlay\"" = " 请使用\"演讲者前置\"功能"; "No Devices Found!" = "未找到任何设备"; "No Cameras Found!" = "未找到任何摄像头"; "Please unlock!" = "请解锁屏幕!"; @@ -140,6 +141,7 @@ " Stop after" = "在"; "Don't remind me again" = "不再提醒"; "OK" = "好"; +"Failed to save file" = "保存文件时出错"; "failed to fetch file for size indicator: %@" = "获取文件大小失败: "; "[err] failed to fetch available content:" = "[错误] 无法获取可用的上下文:";