|
@@ -21,6 +21,12 @@ private enum AppWindowMetrics {
|
|
|
static let defaultContentHeight: CGFloat = 690
|
|
static let defaultContentHeight: CGFloat = 690
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+private enum AppExternalURLs {
|
|
|
|
|
+ static let privacyPolicy = URL(string: "https://sites.google.com/view/aicompanionforzoom/privacy-policy")!
|
|
|
|
|
+ static let termsOfServices = URL(string: "https://sites.google.com/view/aicompanionforzoom/terms-and-condition")!
|
|
|
|
|
+ static let support = URL(string: "https://sites.google.com/view/aicompanionforzoom/get-support")!
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/// Zoom shows "browser not supported" for the default macOS `WKWebView` UA. Use a desktop Safari string so join/start (including `/s/` host links) load in-app.
|
|
/// Zoom shows "browser not supported" for the default macOS `WKWebView` UA. Use a desktop Safari string so join/start (including `/s/` host links) load in-app.
|
|
|
private let embeddedZoomWebViewUserAgent =
|
|
private let embeddedZoomWebViewUserAgent =
|
|
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15"
|
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15"
|
|
@@ -358,7 +364,6 @@ class ViewController: NSViewController {
|
|
|
private var recordedMeetingsPlayer: AVAudioPlayer?
|
|
private var recordedMeetingsPlayer: AVAudioPlayer?
|
|
|
private var recordedMeetingsPlayingID: String?
|
|
private var recordedMeetingsPlayingID: String?
|
|
|
private weak var aiCompanionStopRecordingButton: NSButton?
|
|
private weak var aiCompanionStopRecordingButton: NSButton?
|
|
|
- private weak var aiCompanionOpenRecordingsFolderButton: NSButton?
|
|
|
|
|
private weak var aiCompanionLocalTranscriptPanel: NSPanel?
|
|
private weak var aiCompanionLocalTranscriptPanel: NSPanel?
|
|
|
private weak var aiCompanionLocalTranscriptTextView: NSTextView?
|
|
private weak var aiCompanionLocalTranscriptTextView: NSTextView?
|
|
|
private weak var aiCompanionLocalTranscriptRootView: NSView?
|
|
private weak var aiCompanionLocalTranscriptRootView: NSView?
|
|
@@ -447,7 +452,7 @@ class ViewController: NSViewController {
|
|
|
private var paywallIsDesktopLayout = false
|
|
private var paywallIsDesktopLayout = false
|
|
|
private var paywallPanelWidthConstraint: NSLayoutConstraint?
|
|
private var paywallPanelWidthConstraint: NSLayoutConstraint?
|
|
|
private var paywallPanelHeightConstraint: NSLayoutConstraint?
|
|
private var paywallPanelHeightConstraint: NSLayoutConstraint?
|
|
|
- private var joinMeetingWindow: NSWindow?
|
|
|
|
|
|
|
+ private var joinMeetingWindow: NSPanel?
|
|
|
private var scheduleMeetingWindow: NSWindow?
|
|
private var scheduleMeetingWindow: NSWindow?
|
|
|
private weak var scheduleTopicField: NSTextField?
|
|
private weak var scheduleTopicField: NSTextField?
|
|
|
private weak var scheduleDateField: NSTextField?
|
|
private weak var scheduleDateField: NSTextField?
|
|
@@ -923,7 +928,6 @@ class ViewController: NSViewController {
|
|
|
aiCompanionOpenDocButton = nil
|
|
aiCompanionOpenDocButton = nil
|
|
|
aiCompanionCopyMarkdownButton = nil
|
|
aiCompanionCopyMarkdownButton = nil
|
|
|
aiCompanionStopRecordingButton = nil
|
|
aiCompanionStopRecordingButton = nil
|
|
|
- aiCompanionOpenRecordingsFolderButton = nil
|
|
|
|
|
aiCompanionFilterPopup = nil
|
|
aiCompanionFilterPopup = nil
|
|
|
aiCompanionFilterFromPicker = nil
|
|
aiCompanionFilterFromPicker = nil
|
|
|
aiCompanionFilterToPicker = nil
|
|
aiCompanionFilterToPicker = nil
|
|
@@ -1549,9 +1553,30 @@ class ViewController: NSViewController {
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private func presentJoinMeetingPanel(_ panel: NSPanel) {
|
|
|
|
|
+ guard let host = view.window else {
|
|
|
|
|
+ panel.center()
|
|
|
|
|
+ panel.makeKeyAndOrderFront(nil)
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ if host.attachedSheet !== panel {
|
|
|
|
|
+ host.beginSheet(panel, completionHandler: nil)
|
|
|
|
|
+ }
|
|
|
|
|
+ panel.makeKeyAndOrderFront(nil)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private func dismissJoinMeetingPanel() {
|
|
|
|
|
+ guard let panel = joinMeetingWindow else { return }
|
|
|
|
|
+ if let host = view.window, host.attachedSheet === panel {
|
|
|
|
|
+ host.endSheet(panel)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ panel.performClose(nil)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
@objc private func joinMeetingTapped() {
|
|
@objc private func joinMeetingTapped() {
|
|
|
if let existing = joinMeetingWindow {
|
|
if let existing = joinMeetingWindow {
|
|
|
- existing.makeKeyAndOrderFront(nil)
|
|
|
|
|
|
|
+ presentJoinMeetingPanel(existing)
|
|
|
NSApp.activate(ignoringOtherApps: true)
|
|
NSApp.activate(ignoringOtherApps: true)
|
|
|
DispatchQueue.main.async { [weak self] in
|
|
DispatchQueue.main.async { [weak self] in
|
|
|
_ = self?.joinURLField?.becomeFirstResponder()
|
|
_ = self?.joinURLField?.becomeFirstResponder()
|
|
@@ -1577,17 +1602,18 @@ class ViewController: NSViewController {
|
|
|
panel.standardWindowButton(.closeButton)?.isHidden = true
|
|
panel.standardWindowButton(.closeButton)?.isHidden = true
|
|
|
panel.standardWindowButton(.miniaturizeButton)?.isHidden = true
|
|
panel.standardWindowButton(.miniaturizeButton)?.isHidden = true
|
|
|
panel.standardWindowButton(.zoomButton)?.isHidden = true
|
|
panel.standardWindowButton(.zoomButton)?.isHidden = true
|
|
|
- panel.isMovableByWindowBackground = true
|
|
|
|
|
|
|
+ panel.isFloatingPanel = false
|
|
|
|
|
+ panel.isMovable = false
|
|
|
|
|
+ panel.isMovableByWindowBackground = false
|
|
|
// Allow the panel to become key immediately so text fields receive keyboard input (avoids "can't type" with floating/key heuristics).
|
|
// Allow the panel to become key immediately so text fields receive keyboard input (avoids "can't type" with floating/key heuristics).
|
|
|
panel.becomesKeyOnlyIfNeeded = false
|
|
panel.becomesKeyOnlyIfNeeded = false
|
|
|
panel.appearance = NSAppearance(named: palette.isDarkMode ? .darkAqua : .aqua)
|
|
panel.appearance = NSAppearance(named: palette.isDarkMode ? .darkAqua : .aqua)
|
|
|
- panel.center()
|
|
|
|
|
panel.contentViewController = controller
|
|
panel.contentViewController = controller
|
|
|
panel.delegate = self
|
|
panel.delegate = self
|
|
|
applyWindowBackgroundForCurrentTheme(panel)
|
|
applyWindowBackgroundForCurrentTheme(panel)
|
|
|
- panel.makeKeyAndOrderFront(nil)
|
|
|
|
|
- NSApp.activate(ignoringOtherApps: true)
|
|
|
|
|
joinMeetingWindow = panel
|
|
joinMeetingWindow = panel
|
|
|
|
|
+ presentJoinMeetingPanel(panel)
|
|
|
|
|
+ NSApp.activate(ignoringOtherApps: true)
|
|
|
DispatchQueue.main.async { [weak self] in
|
|
DispatchQueue.main.async { [weak self] in
|
|
|
guard let self else { return }
|
|
guard let self else { return }
|
|
|
_ = self.joinURLField?.becomeFirstResponder()
|
|
_ = self.joinURLField?.becomeFirstResponder()
|
|
@@ -1777,7 +1803,7 @@ class ViewController: NSViewController {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@objc private func joinMeetingCancelTapped() {
|
|
@objc private func joinMeetingCancelTapped() {
|
|
|
- joinMeetingWindow?.performClose(nil)
|
|
|
|
|
|
|
+ dismissJoinMeetingPanel()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@objc private func joinMeetingSubmitTapped() {
|
|
@objc private func joinMeetingSubmitTapped() {
|
|
@@ -2100,7 +2126,7 @@ class ViewController: NSViewController {
|
|
|
opened = openURLInDefaultBrowser(url)
|
|
opened = openURLInDefaultBrowser(url)
|
|
|
}
|
|
}
|
|
|
if opened {
|
|
if opened {
|
|
|
- joinMeetingWindow?.performClose(nil)
|
|
|
|
|
|
|
+ dismissJoinMeetingPanel()
|
|
|
if shouldRecordLocally {
|
|
if shouldRecordLocally {
|
|
|
beginZoomMeetingRecordingIfAppropriate(sourceURL: url, meetingDisplayName: zoomMeetingDisplayName)
|
|
beginZoomMeetingRecordingIfAppropriate(sourceURL: url, meetingDisplayName: zoomMeetingDisplayName)
|
|
|
}
|
|
}
|
|
@@ -4885,11 +4911,11 @@ class ViewController: NSViewController {
|
|
|
case .upgrade:
|
|
case .upgrade:
|
|
|
settingsUpgradePremiumTapped()
|
|
settingsUpgradePremiumTapped()
|
|
|
case .privacyPolicy:
|
|
case .privacyPolicy:
|
|
|
- showSimpleAlert(title: "Privacy Policy", message: "Add your Privacy Policy URL in the app and open it here.")
|
|
|
|
|
|
|
+ openURLInDefaultBrowser(AppExternalURLs.privacyPolicy)
|
|
|
case .support:
|
|
case .support:
|
|
|
- showSimpleAlert(title: "Support", message: "Add your Support URL/email in the app and open it here.")
|
|
|
|
|
|
|
+ openURLInDefaultBrowser(AppExternalURLs.support)
|
|
|
case .termsOfServices:
|
|
case .termsOfServices:
|
|
|
- showSimpleAlert(title: "Terms", message: "Add your Terms URL in the app and open it here.")
|
|
|
|
|
|
|
+ openURLInDefaultBrowser(AppExternalURLs.termsOfServices)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -6242,24 +6268,15 @@ class ViewController: NSViewController {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@objc private func paywallPrivacyPolicyClicked(_ sender: Any?) {
|
|
@objc private func paywallPrivacyPolicyClicked(_ sender: Any?) {
|
|
|
- showSimpleAlert(
|
|
|
|
|
- title: "Privacy Policy",
|
|
|
|
|
- message: "Placeholder: Privacy Policy content/link will be added before publishing."
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ openURLInDefaultBrowser(AppExternalURLs.privacyPolicy)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@objc private func paywallSupportClicked(_ sender: Any?) {
|
|
@objc private func paywallSupportClicked(_ sender: Any?) {
|
|
|
- showSimpleAlert(
|
|
|
|
|
- title: "Support",
|
|
|
|
|
- message: "Placeholder: Support contact details/link will be added before publishing."
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ openURLInDefaultBrowser(AppExternalURLs.support)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@objc private func paywallTermsOfServicesClicked(_ sender: Any?) {
|
|
@objc private func paywallTermsOfServicesClicked(_ sender: Any?) {
|
|
|
- showSimpleAlert(
|
|
|
|
|
- title: "Terms of Services",
|
|
|
|
|
- message: "Placeholder: Terms of Services content/link will be added before publishing."
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ openURLInDefaultBrowser(AppExternalURLs.termsOfServices)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@objc private func paywallManageSubscriptionClicked(_ sender: Any?) {
|
|
@objc private func paywallManageSubscriptionClicked(_ sender: Any?) {
|
|
@@ -7388,18 +7405,7 @@ class ViewController: NSViewController {
|
|
|
stopRecording.font = .systemFont(ofSize: 13, weight: .semibold)
|
|
stopRecording.font = .systemFont(ofSize: 13, weight: .semibold)
|
|
|
stopRecording.isHidden = true
|
|
stopRecording.isHidden = true
|
|
|
|
|
|
|
|
- let openFolder = NSButton(title: "Show folder", target: self, action: #selector(aiCompanionOpenRecordingsFolderTapped))
|
|
|
|
|
- openFolder.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
|
- openFolder.isBordered = false
|
|
|
|
|
- openFolder.wantsLayer = true
|
|
|
|
|
- openFolder.layer?.backgroundColor = (palette.isDarkMode ? NSColor.white.withAlphaComponent(0.08) : NSColor.black.withAlphaComponent(0.06)).cgColor
|
|
|
|
|
- openFolder.layer?.cornerRadius = 10
|
|
|
|
|
- openFolder.layer?.borderWidth = 1
|
|
|
|
|
- openFolder.layer?.borderColor = palette.inputBorder.cgColor
|
|
|
|
|
- openFolder.contentTintColor = primaryText
|
|
|
|
|
- openFolder.font = .systemFont(ofSize: 13, weight: .semibold)
|
|
|
|
|
-
|
|
|
|
|
- let toolbarRight = NSStackView(views: [openFolder, stopRecording, loadingIndicator])
|
|
|
|
|
|
|
+ let toolbarRight = NSStackView(views: [stopRecording, loadingIndicator])
|
|
|
toolbarRight.orientation = .horizontal
|
|
toolbarRight.orientation = .horizontal
|
|
|
toolbarRight.alignment = .centerY
|
|
toolbarRight.alignment = .centerY
|
|
|
toolbarRight.spacing = 10
|
|
toolbarRight.spacing = 10
|
|
@@ -7556,8 +7562,6 @@ class ViewController: NSViewController {
|
|
|
|
|
|
|
|
stopRecording.heightAnchor.constraint(equalToConstant: 30),
|
|
stopRecording.heightAnchor.constraint(equalToConstant: 30),
|
|
|
stopRecording.widthAnchor.constraint(greaterThanOrEqualToConstant: 110),
|
|
stopRecording.widthAnchor.constraint(greaterThanOrEqualToConstant: 110),
|
|
|
- openFolder.heightAnchor.constraint(equalToConstant: 30),
|
|
|
|
|
- openFolder.widthAnchor.constraint(greaterThanOrEqualToConstant: 110),
|
|
|
|
|
|
|
|
|
|
filterBar.topAnchor.constraint(equalTo: titleStack.bottomAnchor, constant: 14),
|
|
filterBar.topAnchor.constraint(equalTo: titleStack.bottomAnchor, constant: 14),
|
|
|
filterBar.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 18),
|
|
filterBar.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 18),
|
|
@@ -7603,7 +7607,6 @@ class ViewController: NSViewController {
|
|
|
aiCompanionDetailScroll = nil
|
|
aiCompanionDetailScroll = nil
|
|
|
aiCompanionDetailStack = nil
|
|
aiCompanionDetailStack = nil
|
|
|
aiCompanionStopRecordingButton = stopRecording
|
|
aiCompanionStopRecordingButton = stopRecording
|
|
|
- aiCompanionOpenRecordingsFolderButton = openFolder
|
|
|
|
|
aiCompanionFilterPopup = categoryFilter
|
|
aiCompanionFilterPopup = categoryFilter
|
|
|
aiCompanionFilterFromPicker = fromDatePicker
|
|
aiCompanionFilterFromPicker = fromDatePicker
|
|
|
aiCompanionFilterToPicker = toDatePicker
|
|
aiCompanionFilterToPicker = toDatePicker
|
|
@@ -7735,10 +7738,6 @@ class ViewController: NSViewController {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- @objc private func aiCompanionOpenRecordingsFolderTapped() {
|
|
|
|
|
- MeetingRecordingManager.shared.revealRecordingsInFinder()
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
// MARK: - AI Companion list / detail rendering
|
|
// MARK: - AI Companion list / detail rendering
|
|
|
|
|
|
|
|
@MainActor
|
|
@MainActor
|
|
@@ -9911,6 +9910,10 @@ extension ViewController: WKNavigationDelegate, WKUIDelegate {
|
|
|
|
|
|
|
|
extension ViewController: NSWindowDelegate {
|
|
extension ViewController: NSWindowDelegate {
|
|
|
func windowShouldClose(_ sender: NSWindow) -> Bool {
|
|
func windowShouldClose(_ sender: NSWindow) -> Bool {
|
|
|
|
|
+ if let panel = joinMeetingWindow, sender === panel, let host = view.window {
|
|
|
|
|
+ host.endSheet(panel)
|
|
|
|
|
+ return false
|
|
|
|
|
+ }
|
|
|
if let panel = aiCompanionLocalTranscriptPanel, sender === panel, let host = view.window {
|
|
if let panel = aiCompanionLocalTranscriptPanel, sender === panel, let host = view.window {
|
|
|
host.endSheet(panel)
|
|
host.endSheet(panel)
|
|
|
return false
|
|
return false
|