|
@@ -1736,10 +1736,7 @@ class ViewController: NSViewController {
|
|
|
}
|
|
}
|
|
|
guard let url = zoomURL else { return }
|
|
guard let url = zoomURL else { return }
|
|
|
|
|
|
|
|
- let consentChoice = requestMeetingRecordingConsent(title: "Join Meeting")
|
|
|
|
|
- if consentChoice == .dismissed { return }
|
|
|
|
|
- let shouldRecord = (consentChoice == .allowAndContinue)
|
|
|
|
|
- openZoomMeetingInDefaultBrowser(url, meetingDisplayName: meetingName, recordLocally: shouldRecord)
|
|
|
|
|
|
|
+ openWebURLPreferringInApp(url, zoomMeetingDisplayName: meetingName, recordingConsentWindowTitle: "Join Meeting")
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private enum MeetingRecordingConsentChoice {
|
|
private enum MeetingRecordingConsentChoice {
|
|
@@ -1751,7 +1748,7 @@ class ViewController: NSViewController {
|
|
|
private func requestMeetingRecordingConsent(title: String) -> MeetingRecordingConsentChoice {
|
|
private func requestMeetingRecordingConsent(title: String) -> MeetingRecordingConsentChoice {
|
|
|
let alert = NSAlert()
|
|
let alert = NSAlert()
|
|
|
alert.messageText = "Record this meeting locally?"
|
|
alert.messageText = "Record this meeting locally?"
|
|
|
- alert.informativeText = "With your consent, the app will record meeting audio on this Mac and show it in Ai Companion after the meeting."
|
|
|
|
|
|
|
+ alert.informativeText = "With your consent, the app will record meeting audio on this Mac and show it in AI Companion after the meeting."
|
|
|
alert.addButton(withTitle: "Allow and Continue")
|
|
alert.addButton(withTitle: "Allow and Continue")
|
|
|
alert.addButton(withTitle: "Continue Without Recording")
|
|
alert.addButton(withTitle: "Continue Without Recording")
|
|
|
alert.window.title = title
|
|
alert.window.title = title
|
|
@@ -1873,6 +1870,7 @@ class ViewController: NSViewController {
|
|
|
secondary = nil
|
|
secondary = nil
|
|
|
}
|
|
}
|
|
|
TranscriptionLanguagePreferences.updatePreferredLanguages(primary: primary, secondary: secondary)
|
|
TranscriptionLanguagePreferences.updatePreferredLanguages(primary: primary, secondary: secondary)
|
|
|
|
|
+ syncSettingsSpeechLanguagePopupsFromStoredPreferences()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
switch response {
|
|
switch response {
|
|
@@ -1906,6 +1904,25 @@ class ViewController: NSViewController {
|
|
|
meetingConsentSecondaryLanguagePopup?.selectItem(at: 0)
|
|
meetingConsentSecondaryLanguagePopup?.selectItem(at: 0)
|
|
|
}
|
|
}
|
|
|
TranscriptionLanguagePreferences.updatePreferredLanguages(primary: primary, secondary: secondary)
|
|
TranscriptionLanguagePreferences.updatePreferredLanguages(primary: primary, secondary: secondary)
|
|
|
|
|
+ syncSettingsSpeechLanguagePopupsFromStoredPreferences()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// Keeps Settings language menus aligned when preferences change from the pre-join consent sheet.
|
|
|
|
|
+ private func syncSettingsSpeechLanguagePopupsFromStoredPreferences() {
|
|
|
|
|
+ let options = TranscriptionLanguagePreferences.supportedSpeechLocaleOptions()
|
|
|
|
|
+ if let primaryPopup = settingsPagePrimaryLanguagePopup {
|
|
|
|
|
+ let id = TranscriptionLanguagePreferences.selectedPrimaryIdentifier()
|
|
|
|
|
+ ?? options.first?.identifier
|
|
|
|
|
+ ?? Locale.current.identifier
|
|
|
|
|
+ selectTranscriptionLanguage(identifier: id, in: primaryPopup)
|
|
|
|
|
+ }
|
|
|
|
|
+ if let secondaryPopup = settingsPageSecondaryLanguagePopup {
|
|
|
|
|
+ if let selected = TranscriptionLanguagePreferences.selectedSecondaryIdentifier() {
|
|
|
|
|
+ selectTranscriptionLanguage(identifier: selected, in: secondaryPopup)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ secondaryPopup.selectItem(at: 0)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private func selectTranscriptionLanguage(identifier: String, in popup: NSPopUpButton) {
|
|
private func selectTranscriptionLanguage(identifier: String, in popup: NSPopUpButton) {
|
|
@@ -1948,11 +1965,32 @@ class ViewController: NSViewController {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// Opens non-sign-in web content in the system default browser.
|
|
/// Opens non-sign-in web content in the system default browser.
|
|
|
- /// For Zoom meeting join/start links, also begins local audio recording (when not already recording), same as the Join flow.
|
|
|
|
|
|
|
+ /// For Zoom meeting join/start links, asks for recording consent first, persists transcription languages from that sheet,
|
|
|
|
|
+ /// then optionally begins local audio recording (when the user allows and recording is not already active).
|
|
|
@MainActor
|
|
@MainActor
|
|
|
- private func openWebURLPreferringInApp(_ url: URL, zoomMeetingDisplayName: String? = nil) {
|
|
|
|
|
- _ = openURLInDefaultBrowser(url)
|
|
|
|
|
- beginZoomMeetingRecordingIfAppropriate(sourceURL: url, meetingDisplayName: zoomMeetingDisplayName)
|
|
|
|
|
|
|
+ private func openWebURLPreferringInApp(
|
|
|
|
|
+ _ url: URL,
|
|
|
|
|
+ zoomMeetingDisplayName: String? = nil,
|
|
|
|
|
+ recordingConsentWindowTitle: String = "Meeting"
|
|
|
|
|
+ ) {
|
|
|
|
|
+ let shouldRecordLocally: Bool
|
|
|
|
|
+ if isZoomMeetingJoinOrStartURL(url) {
|
|
|
|
|
+ let consentChoice = requestMeetingRecordingConsent(title: recordingConsentWindowTitle)
|
|
|
|
|
+ if consentChoice == .dismissed { return }
|
|
|
|
|
+ shouldRecordLocally = (consentChoice == .allowAndContinue)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ shouldRecordLocally = false
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ let opened = openURLInDefaultBrowser(url)
|
|
|
|
|
+ if opened {
|
|
|
|
|
+ joinMeetingWindow?.performClose(nil)
|
|
|
|
|
+ if shouldRecordLocally {
|
|
|
|
|
+ beginZoomMeetingRecordingIfAppropriate(sourceURL: url, meetingDisplayName: zoomMeetingDisplayName)
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ showSimpleAlert(title: "Unable to open", message: "Your default browser could not be opened.")
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// True when `url` looks like joining or starting a Zoom call (not OAuth, API, or generic marketing pages).
|
|
/// True when `url` looks like joining or starting a Zoom call (not OAuth, API, or generic marketing pages).
|
|
@@ -1985,19 +2023,6 @@ class ViewController: NSViewController {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- @MainActor
|
|
|
|
|
- private func openZoomMeetingInDefaultBrowser(_ url: URL, meetingDisplayName: String? = nil, recordLocally: Bool = true) {
|
|
|
|
|
- let opened = openURLInDefaultBrowser(url)
|
|
|
|
|
- if opened {
|
|
|
|
|
- joinMeetingWindow?.performClose(nil)
|
|
|
|
|
- if recordLocally {
|
|
|
|
|
- beginZoomMeetingRecordingIfAppropriate(sourceURL: url, meetingDisplayName: meetingDisplayName)
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- showSimpleAlert(title: "Unable to open", message: "Your default browser could not be opened.")
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
@discardableResult
|
|
@discardableResult
|
|
|
private func openURLInDefaultBrowser(_ url: URL) -> Bool {
|
|
private func openURLInDefaultBrowser(_ url: URL) -> Bool {
|
|
|
NSWorkspace.shared.open(url)
|
|
NSWorkspace.shared.open(url)
|
|
@@ -2562,7 +2587,7 @@ class ViewController: NSViewController {
|
|
|
@objc private func meetingSearchResultTapped(_ sender: NSButton) {
|
|
@objc private func meetingSearchResultTapped(_ sender: NSButton) {
|
|
|
guard let meeting = globalSearchResults[safe: sender.tag] else { return }
|
|
guard let meeting = globalSearchResults[safe: sender.tag] else { return }
|
|
|
if let url = meeting.webURL {
|
|
if let url = meeting.webURL {
|
|
|
- openWebURLPreferringInApp(url, zoomMeetingDisplayName: meeting.title)
|
|
|
|
|
|
|
+ openWebURLPreferringInApp(url, zoomMeetingDisplayName: meeting.title, recordingConsentWindowTitle: "Join Meeting")
|
|
|
} else {
|
|
} else {
|
|
|
let pasteboard = NSPasteboard.general
|
|
let pasteboard = NSPasteboard.general
|
|
|
pasteboard.clearContents()
|
|
pasteboard.clearContents()
|
|
@@ -8236,7 +8261,7 @@ class ViewController: NSViewController {
|
|
|
guard let self else { return }
|
|
guard let self else { return }
|
|
|
guard let link = notification.userInfo?["link"] as? String,
|
|
guard let link = notification.userInfo?["link"] as? String,
|
|
|
let url = URL(string: link.trimmingCharacters(in: .whitespacesAndNewlines)) else { return }
|
|
let url = URL(string: link.trimmingCharacters(in: .whitespacesAndNewlines)) else { return }
|
|
|
- self.openWebURLPreferringInApp(url, zoomMeetingDisplayName: nil)
|
|
|
|
|
|
|
+ self.openWebURLPreferringInApp(url, zoomMeetingDisplayName: nil, recordingConsentWindowTitle: "Join Meeting")
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -8705,7 +8730,7 @@ class ViewController: NSViewController {
|
|
|
showSimpleAlert(title: "Unable to open", message: "Could not start a new Zoom meeting right now.")
|
|
showSimpleAlert(title: "Unable to open", message: "Could not start a new Zoom meeting right now.")
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
- openWebURLPreferringInApp(url, zoomMeetingDisplayName: "Instant meeting")
|
|
|
|
|
|
|
+ openWebURLPreferringInApp(url, zoomMeetingDisplayName: "Instant meeting", recordingConsentWindowTitle: "New Meeting")
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func menuBarTriggerJoinMeeting() {
|
|
func menuBarTriggerJoinMeeting() {
|
|
@@ -9023,7 +9048,7 @@ class ViewController: NSViewController {
|
|
|
hoverBackground: hoverBackground,
|
|
hoverBackground: hoverBackground,
|
|
|
hoverBorder: hoverBorder,
|
|
hoverBorder: hoverBorder,
|
|
|
onTapURL: { [weak self] url in
|
|
onTapURL: { [weak self] url in
|
|
|
- self?.openWebURLPreferringInApp(url, zoomMeetingDisplayName: meeting.title)
|
|
|
|
|
|
|
+ self?.openWebURLPreferringInApp(url, zoomMeetingDisplayName: meeting.title, recordingConsentWindowTitle: "Join Meeting")
|
|
|
}
|
|
}
|
|
|
)
|
|
)
|
|
|
card.wantsLayer = true
|
|
card.wantsLayer = true
|