|
@@ -334,8 +334,10 @@ final class ViewController: NSViewController {
|
|
|
private var aiCompanionNotesMeetingIdByView = [ObjectIdentifier: String]()
|
|
private var aiCompanionNotesMeetingIdByView = [ObjectIdentifier: String]()
|
|
|
private var aiCompanionNotesStatusLabelByView = [ObjectIdentifier: NSTextField]()
|
|
private var aiCompanionNotesStatusLabelByView = [ObjectIdentifier: NSTextField]()
|
|
|
private var aiCompanionNotesCurrentRequestId: UUID?
|
|
private var aiCompanionNotesCurrentRequestId: UUID?
|
|
|
- private var aiCompanionNotesWindow: NSWindow?
|
|
|
|
|
|
|
+ private var aiCompanionNotesPanel: NSPanel?
|
|
|
private weak var aiCompanionNotesTextView: NSTextView?
|
|
private weak var aiCompanionNotesTextView: NSTextView?
|
|
|
|
|
+ private weak var aiCompanionNotesCopyButton: NSButton?
|
|
|
|
|
+ private weak var aiCompanionNotesCloseButton: NSButton?
|
|
|
private var aiCompanionNotesTaskByMeetingId = [String: Task<Void, Never>]()
|
|
private var aiCompanionNotesTaskByMeetingId = [String: Task<Void, Never>]()
|
|
|
private var aiCompanionAudioPlayer: AVPlayer?
|
|
private var aiCompanionAudioPlayer: AVPlayer?
|
|
|
private var aiCompanionLocalAudioPlayer: AVAudioPlayer?
|
|
private var aiCompanionLocalAudioPlayer: AVAudioPlayer?
|
|
@@ -3522,58 +3524,148 @@ private extension ViewController {
|
|
|
|
|
|
|
|
@MainActor
|
|
@MainActor
|
|
|
private func aiCompanionPresentNotesWindow(meetingTitle: String, initialText: String) {
|
|
private func aiCompanionPresentNotesWindow(meetingTitle: String, initialText: String) {
|
|
|
- if let window = aiCompanionNotesWindow, let textView = aiCompanionNotesTextView {
|
|
|
|
|
- window.title = "Notes - \(meetingTitle)"
|
|
|
|
|
|
|
+ guard let hostWindow = view.window else { return }
|
|
|
|
|
+ let hostIsDarkMode = hostWindow.effectiveAppearance.bestMatch(from: [.darkAqua, .aqua]) == .darkAqua
|
|
|
|
|
+ let panelAppearanceName: NSAppearance.Name = hostIsDarkMode ? .darkAqua : .aqua
|
|
|
|
|
+ let outerBackgroundColor: NSColor = hostIsDarkMode ? .windowBackgroundColor : NSColor(calibratedWhite: 0.96, alpha: 1.0)
|
|
|
|
|
+ let headerBackgroundColor: NSColor = hostIsDarkMode ? .controlBackgroundColor : NSColor(calibratedWhite: 0.93, alpha: 1.0)
|
|
|
|
|
+
|
|
|
|
|
+ if let panel = aiCompanionNotesPanel, let textView = aiCompanionNotesTextView {
|
|
|
|
|
+ panel.title = "Notes - \(meetingTitle)"
|
|
|
|
|
+ panel.appearance = NSAppearance(named: panelAppearanceName)
|
|
|
|
|
+ panel.backgroundColor = outerBackgroundColor
|
|
|
textView.string = initialText
|
|
textView.string = initialText
|
|
|
- window.makeKeyAndOrderFront(nil)
|
|
|
|
|
|
|
+ if hostWindow.attachedSheet !== panel {
|
|
|
|
|
+ hostWindow.beginSheet(panel, completionHandler: nil)
|
|
|
|
|
+ }
|
|
|
|
|
+ panel.makeKeyAndOrderFront(nil)
|
|
|
NSApp.activate(ignoringOtherApps: true)
|
|
NSApp.activate(ignoringOtherApps: true)
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- let windowWidth: CGFloat = 640
|
|
|
|
|
- let windowHeight: CGFloat = 560
|
|
|
|
|
- let window = NSWindow(
|
|
|
|
|
- contentRect: NSRect(x: 0, y: 0, width: windowWidth, height: windowHeight),
|
|
|
|
|
- styleMask: [.titled, .closable, .resizable],
|
|
|
|
|
|
|
+ let panelWidth: CGFloat = 720
|
|
|
|
|
+ let panelHeight: CGFloat = 540
|
|
|
|
|
+ let panel = NSPanel(
|
|
|
|
|
+ contentRect: NSRect(x: 0, y: 0, width: panelWidth, height: panelHeight),
|
|
|
|
|
+ styleMask: [.titled, .closable],
|
|
|
backing: .buffered,
|
|
backing: .buffered,
|
|
|
defer: false
|
|
defer: false
|
|
|
)
|
|
)
|
|
|
- window.isReleasedWhenClosed = false
|
|
|
|
|
- window.title = "Notes - \(meetingTitle)"
|
|
|
|
|
- window.center()
|
|
|
|
|
|
|
+ panel.isReleasedWhenClosed = false
|
|
|
|
|
+ panel.title = "Notes - \(meetingTitle)"
|
|
|
|
|
+ panel.isFloatingPanel = false
|
|
|
|
|
+ panel.hidesOnDeactivate = false
|
|
|
|
|
+ panel.delegate = self
|
|
|
|
|
+ panel.appearance = NSAppearance(named: panelAppearanceName)
|
|
|
|
|
+ panel.backgroundColor = outerBackgroundColor
|
|
|
|
|
+ panel.standardWindowButton(.zoomButton)?.isHidden = true
|
|
|
|
|
+ panel.standardWindowButton(.miniaturizeButton)?.isHidden = true
|
|
|
|
|
|
|
|
let root = NSView()
|
|
let root = NSView()
|
|
|
root.translatesAutoresizingMaskIntoConstraints = false
|
|
root.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
|
+ root.wantsLayer = true
|
|
|
|
|
+ root.layer?.backgroundColor = outerBackgroundColor.cgColor
|
|
|
|
|
+
|
|
|
|
|
+ let header = NSView()
|
|
|
|
|
+ header.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
|
+ header.wantsLayer = true
|
|
|
|
|
+ header.layer?.backgroundColor = headerBackgroundColor.cgColor
|
|
|
|
|
+ header.layer?.cornerRadius = 10
|
|
|
|
|
+
|
|
|
|
|
+ let titleLabel = textLabel("Meeting Notes", font: NSFont.systemFont(ofSize: 15, weight: .semibold), color: .labelColor)
|
|
|
|
|
+ titleLabel.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
|
+ let subtitleLabel = textLabel(meetingTitle, font: NSFont.systemFont(ofSize: 12, weight: .regular), color: .secondaryLabelColor)
|
|
|
|
|
+ subtitleLabel.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
|
+ subtitleLabel.lineBreakMode = .byTruncatingTail
|
|
|
|
|
|
|
|
let scroll = NSScrollView()
|
|
let scroll = NSScrollView()
|
|
|
scroll.translatesAutoresizingMaskIntoConstraints = false
|
|
scroll.translatesAutoresizingMaskIntoConstraints = false
|
|
|
- scroll.drawsBackground = false
|
|
|
|
|
|
|
+ scroll.drawsBackground = true
|
|
|
|
|
+ scroll.backgroundColor = NSColor.textBackgroundColor
|
|
|
scroll.hasVerticalScroller = true
|
|
scroll.hasVerticalScroller = true
|
|
|
|
|
+ scroll.hasHorizontalScroller = false
|
|
|
|
|
+ scroll.borderType = .bezelBorder
|
|
|
|
|
|
|
|
let textView = NSTextView()
|
|
let textView = NSTextView()
|
|
|
textView.isEditable = false
|
|
textView.isEditable = false
|
|
|
textView.isSelectable = true
|
|
textView.isSelectable = true
|
|
|
- textView.backgroundColor = .clear
|
|
|
|
|
|
|
+ textView.backgroundColor = NSColor.textBackgroundColor
|
|
|
|
|
+ textView.textColor = NSColor.labelColor
|
|
|
textView.font = NSFont.systemFont(ofSize: 13, weight: .regular)
|
|
textView.font = NSFont.systemFont(ofSize: 13, weight: .regular)
|
|
|
textView.string = initialText
|
|
textView.string = initialText
|
|
|
textView.textContainer?.widthTracksTextView = true
|
|
textView.textContainer?.widthTracksTextView = true
|
|
|
|
|
+ textView.textContainerInset = NSSize(width: 10, height: 10)
|
|
|
|
|
+
|
|
|
|
|
+ let copyButton = NSButton(title: "Copy", target: self, action: #selector(aiCompanionCopyNotesTapped(_:)))
|
|
|
|
|
+ copyButton.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
|
+ copyButton.bezelStyle = .rounded
|
|
|
|
|
+
|
|
|
|
|
+ let closeButton = NSButton(title: "Close", target: self, action: #selector(aiCompanionCloseNotesTapped(_:)))
|
|
|
|
|
+ closeButton.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
|
+ closeButton.bezelStyle = .rounded
|
|
|
|
|
|
|
|
scroll.documentView = textView
|
|
scroll.documentView = textView
|
|
|
|
|
+ header.addSubview(titleLabel)
|
|
|
|
|
+ header.addSubview(subtitleLabel)
|
|
|
|
|
+ header.addSubview(copyButton)
|
|
|
|
|
+ header.addSubview(closeButton)
|
|
|
|
|
+ root.addSubview(header)
|
|
|
root.addSubview(scroll)
|
|
root.addSubview(scroll)
|
|
|
|
|
|
|
|
NSLayoutConstraint.activate([
|
|
NSLayoutConstraint.activate([
|
|
|
- scroll.leadingAnchor.constraint(equalTo: root.leadingAnchor),
|
|
|
|
|
- scroll.trailingAnchor.constraint(equalTo: root.trailingAnchor),
|
|
|
|
|
- scroll.topAnchor.constraint(equalTo: root.topAnchor),
|
|
|
|
|
- scroll.bottomAnchor.constraint(equalTo: root.bottomAnchor)
|
|
|
|
|
|
|
+ header.topAnchor.constraint(equalTo: root.topAnchor, constant: 12),
|
|
|
|
|
+ header.leadingAnchor.constraint(equalTo: root.leadingAnchor, constant: 16),
|
|
|
|
|
+ header.trailingAnchor.constraint(equalTo: root.trailingAnchor, constant: -16),
|
|
|
|
|
+
|
|
|
|
|
+ titleLabel.topAnchor.constraint(equalTo: header.topAnchor, constant: 12),
|
|
|
|
|
+ titleLabel.leadingAnchor.constraint(equalTo: header.leadingAnchor, constant: 12),
|
|
|
|
|
+ titleLabel.trailingAnchor.constraint(lessThanOrEqualTo: copyButton.leadingAnchor, constant: -12),
|
|
|
|
|
+
|
|
|
|
|
+ subtitleLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 4),
|
|
|
|
|
+ subtitleLabel.leadingAnchor.constraint(equalTo: header.leadingAnchor, constant: 12),
|
|
|
|
|
+ subtitleLabel.trailingAnchor.constraint(lessThanOrEqualTo: copyButton.leadingAnchor, constant: -12),
|
|
|
|
|
+ subtitleLabel.bottomAnchor.constraint(equalTo: header.bottomAnchor, constant: -12),
|
|
|
|
|
+
|
|
|
|
|
+ copyButton.centerYAnchor.constraint(equalTo: header.centerYAnchor),
|
|
|
|
|
+ copyButton.trailingAnchor.constraint(equalTo: closeButton.leadingAnchor, constant: -8),
|
|
|
|
|
+
|
|
|
|
|
+ closeButton.centerYAnchor.constraint(equalTo: header.centerYAnchor),
|
|
|
|
|
+ closeButton.trailingAnchor.constraint(equalTo: header.trailingAnchor, constant: -12),
|
|
|
|
|
+
|
|
|
|
|
+ scroll.topAnchor.constraint(equalTo: header.bottomAnchor, constant: 12),
|
|
|
|
|
+ scroll.leadingAnchor.constraint(equalTo: root.leadingAnchor, constant: 16),
|
|
|
|
|
+ scroll.trailingAnchor.constraint(equalTo: root.trailingAnchor, constant: -16),
|
|
|
|
|
+ scroll.bottomAnchor.constraint(equalTo: root.bottomAnchor, constant: -16)
|
|
|
])
|
|
])
|
|
|
|
|
|
|
|
- window.contentView = root
|
|
|
|
|
- window.makeKeyAndOrderFront(nil)
|
|
|
|
|
|
|
+ panel.contentView = root
|
|
|
|
|
+ hostWindow.beginSheet(panel, completionHandler: nil)
|
|
|
|
|
+ panel.makeKeyAndOrderFront(nil)
|
|
|
NSApp.activate(ignoringOtherApps: true)
|
|
NSApp.activate(ignoringOtherApps: true)
|
|
|
|
|
|
|
|
- aiCompanionNotesWindow = window
|
|
|
|
|
|
|
+ aiCompanionNotesPanel = panel
|
|
|
aiCompanionNotesTextView = textView
|
|
aiCompanionNotesTextView = textView
|
|
|
|
|
+ aiCompanionNotesCopyButton = copyButton
|
|
|
|
|
+ aiCompanionNotesCloseButton = closeButton
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @objc private func aiCompanionCopyNotesTapped(_ sender: NSButton) {
|
|
|
|
|
+ guard let notes = aiCompanionNotesTextView?.string, notes.isEmpty == false else { return }
|
|
|
|
|
+ NSPasteboard.general.clearContents()
|
|
|
|
|
+ NSPasteboard.general.setString(notes, forType: .string)
|
|
|
|
|
+ sender.title = "Copied"
|
|
|
|
|
+ DispatchQueue.main.asyncAfter(deadline: .now() + 1.2) { [weak self] in
|
|
|
|
|
+ guard self?.aiCompanionNotesCopyButton === sender else { return }
|
|
|
|
|
+ sender.title = "Copy"
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @objc private func aiCompanionCloseNotesTapped(_ sender: NSButton) {
|
|
|
|
|
+ guard let panel = aiCompanionNotesPanel else { return }
|
|
|
|
|
+ if let hostWindow = view.window, hostWindow.attachedSheet === panel {
|
|
|
|
|
+ hostWindow.endSheet(panel)
|
|
|
|
|
+ }
|
|
|
|
|
+ panel.orderOut(nil)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private func aiCompanionMeetMeetingCode(from meetURL: URL) -> String? {
|
|
private func aiCompanionMeetMeetingCode(from meetURL: URL) -> String? {
|
|
@@ -6513,6 +6605,13 @@ extension ViewController: AVAudioPlayerDelegate {
|
|
|
extension ViewController: NSWindowDelegate {
|
|
extension ViewController: NSWindowDelegate {
|
|
|
func windowWillClose(_ notification: Notification) {
|
|
func windowWillClose(_ notification: Notification) {
|
|
|
guard let closingWindow = notification.object as? NSWindow else { return }
|
|
guard let closingWindow = notification.object as? NSWindow else { return }
|
|
|
|
|
+ if closingWindow === aiCompanionNotesPanel {
|
|
|
|
|
+ aiCompanionNotesPanel = nil
|
|
|
|
|
+ aiCompanionNotesTextView = nil
|
|
|
|
|
+ aiCompanionNotesCopyButton = nil
|
|
|
|
|
+ aiCompanionNotesCloseButton = nil
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
if closingWindow === paywallWindow {
|
|
if closingWindow === paywallWindow {
|
|
|
paywallWindow = nil
|
|
paywallWindow = nil
|
|
|
paywallUpgradeFlowEnabled = false
|
|
paywallUpgradeFlowEnabled = false
|