|
|
@@ -3235,6 +3235,59 @@ private extension ViewController {
|
|
|
stack.bottomAnchor.constraint(equalTo: card.bottomAnchor, constant: -14)
|
|
|
])
|
|
|
|
|
|
+ if !storeKitCoordinator.hasPremiumAccess {
|
|
|
+ // Keep the content present (so layout stays stable), but visually lock it and route clicks to the paywall.
|
|
|
+ notesButton.isEnabled = false
|
|
|
+
|
|
|
+ let lockOverlay = NSVisualEffectView()
|
|
|
+ lockOverlay.translatesAutoresizingMaskIntoConstraints = false
|
|
|
+ lockOverlay.material = darkModeEnabled ? .hudWindow : .popover
|
|
|
+ lockOverlay.blendingMode = .withinWindow
|
|
|
+ lockOverlay.state = .active
|
|
|
+ lockOverlay.wantsLayer = true
|
|
|
+ lockOverlay.layer?.cornerRadius = 14
|
|
|
+ lockOverlay.layer?.masksToBounds = true
|
|
|
+ lockOverlay.layer?.backgroundColor = NSColor.black.withAlphaComponent(darkModeEnabled ? 0.30 : 0.12).cgColor
|
|
|
+ card.addSubview(lockOverlay)
|
|
|
+
|
|
|
+ let message = textLabel(
|
|
|
+ "Premium required. Click to unlock AI Companion notes.",
|
|
|
+ font: NSFont.systemFont(ofSize: 13, weight: .semibold),
|
|
|
+ color: darkModeEnabled ? .white : .black
|
|
|
+ )
|
|
|
+ message.alignment = .center
|
|
|
+ message.maximumNumberOfLines = 2
|
|
|
+ message.lineBreakMode = .byWordWrapping
|
|
|
+ lockOverlay.addSubview(message)
|
|
|
+
|
|
|
+ let hit = HoverTrackingView()
|
|
|
+ hit.translatesAutoresizingMaskIntoConstraints = false
|
|
|
+ hit.wantsLayer = true
|
|
|
+ hit.layer?.backgroundColor = NSColor.clear.cgColor
|
|
|
+ hit.onClick = { [weak self] in
|
|
|
+ self?.showPaywall()
|
|
|
+ }
|
|
|
+ hit.toolTip = "Premium required. Click to open paywall."
|
|
|
+ lockOverlay.addSubview(hit)
|
|
|
+
|
|
|
+ NSLayoutConstraint.activate([
|
|
|
+ lockOverlay.leadingAnchor.constraint(equalTo: card.leadingAnchor),
|
|
|
+ lockOverlay.trailingAnchor.constraint(equalTo: card.trailingAnchor),
|
|
|
+ lockOverlay.topAnchor.constraint(equalTo: card.topAnchor),
|
|
|
+ lockOverlay.bottomAnchor.constraint(equalTo: card.bottomAnchor),
|
|
|
+
|
|
|
+ message.centerXAnchor.constraint(equalTo: lockOverlay.centerXAnchor),
|
|
|
+ message.centerYAnchor.constraint(equalTo: lockOverlay.centerYAnchor),
|
|
|
+ message.leadingAnchor.constraint(greaterThanOrEqualTo: lockOverlay.leadingAnchor, constant: 18),
|
|
|
+ message.trailingAnchor.constraint(lessThanOrEqualTo: lockOverlay.trailingAnchor, constant: -18),
|
|
|
+
|
|
|
+ hit.leadingAnchor.constraint(equalTo: lockOverlay.leadingAnchor),
|
|
|
+ hit.trailingAnchor.constraint(equalTo: lockOverlay.trailingAnchor),
|
|
|
+ hit.topAnchor.constraint(equalTo: lockOverlay.topAnchor),
|
|
|
+ hit.bottomAnchor.constraint(equalTo: lockOverlay.bottomAnchor)
|
|
|
+ ])
|
|
|
+ }
|
|
|
+
|
|
|
return card
|
|
|
}
|
|
|
|
|
|
@@ -3706,6 +3759,10 @@ private extension ViewController {
|
|
|
}
|
|
|
|
|
|
@objc private func aiCompanionNotesTapped(_ sender: NSButton) {
|
|
|
+ guard storeKitCoordinator.hasPremiumAccess else {
|
|
|
+ showPaywall()
|
|
|
+ return
|
|
|
+ }
|
|
|
let senderId = ObjectIdentifier(sender)
|
|
|
guard let meetingId = aiCompanionNotesMeetingIdByView[senderId] else { return }
|
|
|
guard let recording = aiCompanionLocalRecordings.first(where: { $0.id == meetingId }) else {
|