Working and Hidden - with gemini api

This commit is contained in:
Hariharan Mudaliar 2025-09-22 00:59:03 +05:30
commit fb4f7a92c4
4 changed files with 236 additions and 522 deletions

View file

@ -606,18 +606,38 @@ struct StreamingChatMessageBubble: View {
struct ScreenshotButton: View {
@ObservedObject var screenAssistantManager = ScreenAssistantManager.shared
@StateObject private var screenshotTool = ScreenshotSnippingTool.shared
@State private var showingScreenshotOptions = false
var body: some View {
Button(action: startScreenshot) {
Image(systemName: getIconName())
.foregroundColor(getIconColor())
.font(.system(size: 20))
HStack(spacing: 4) {
// Main screenshot button
Button(action: startQuickScreenshot) {
Image(systemName: getIconName())
.foregroundColor(getIconColor())
.font(.system(size: 20))
}
.buttonStyle(PlainButtonStyle())
.help("Take area screenshot")
.disabled(screenshotTool.isSnipping)
.scaleEffect(screenshotTool.isSnipping ? 1.1 : 1.0)
.animation(.easeInOut(duration: 0.2), value: screenshotTool.isSnipping)
// Options dropdown button
Button(action: { showingScreenshotOptions.toggle() }) {
Image(systemName: "chevron.down")
.foregroundColor(.secondary)
.font(.system(size: 12))
}
.buttonStyle(PlainButtonStyle())
.help("Screenshot options")
.disabled(screenshotTool.isSnipping)
.popover(isPresented: $showingScreenshotOptions) {
ScreenshotOptionsPopover { type in
startScreenshot(type: type)
showingScreenshotOptions = false
}
}
}
.buttonStyle(PlainButtonStyle())
.help(getHelpText())
.disabled(screenshotTool.isSnipping)
.scaleEffect(screenshotTool.isSnipping ? 1.1 : 1.0)
.animation(.easeInOut(duration: 0.2), value: screenshotTool.isSnipping)
}
private func getIconName() -> String {
@ -636,21 +656,22 @@ struct ScreenshotButton: View {
}
}
private func getHelpText() -> String {
return screenshotTool.isSnipping ? "Taking screenshot..." : "Take screenshot"
private func startQuickScreenshot() {
// Default to area screenshot for quick action
startScreenshot(type: .area)
}
private func startScreenshot() {
private func startScreenshot(type: ScreenshotSnippingTool.ScreenshotType) {
// Start snipping with direct callback (ScreenshotApp-based approach)
screenshotTool.startSnipping { [weak screenAssistantManager] screenshotURL in
screenshotTool.startSnipping(type: type) { [weak screenAssistantManager] screenshotURL in
guard let manager = screenAssistantManager else {
print("❌ ScreenshotTool: ScreenAssistantManager deallocated during callback")
return
}
print("📁 ScreenshotTool: Adding screenshot to chat: \(screenshotURL.lastPathComponent)")
print("📁 ScreenshotTool: Adding \(type.displayName.lowercased()) screenshot to chat: \(screenshotURL.lastPathComponent)")
manager.addFiles([screenshotURL])
print("📸 Screenshot captured and added to chat successfully")
print("📸 \(type.displayName) screenshot captured and added to chat successfully")
}
}
}
@ -669,4 +690,141 @@ struct ChatPanelsVisualEffectView: NSViewRepresentable {
}
func updateNSView(_ nsView: NSVisualEffectView, context: Context) {}
}
// MARK: - Screenshot Options Popover (Hidden from Screen Recording)
struct ScreenshotOptionsPopover: View {
let onOptionSelected: (ScreenshotSnippingTool.ScreenshotType) -> Void
var body: some View {
VStack(spacing: 8) {
Text("Screenshot Type")
.font(.headline)
.padding(.top, 8)
VStack(spacing: 4) {
ScreenshotOptionButton(
type: .area,
description: "Select an area",
onTap: onOptionSelected
)
ScreenshotOptionButton(
type: .window,
description: "Select a window",
onTap: onOptionSelected
)
ScreenshotOptionButton(
type: .full,
description: "Capture full screen",
onTap: onOptionSelected
)
}
.padding(.bottom, 8)
}
.padding(.horizontal, 12)
.frame(width: 200)
.background(
ScreenshotPopoverBackground()
)
}
}
// MARK: - Screenshot Option Button
struct ScreenshotOptionButton: View {
let type: ScreenshotSnippingTool.ScreenshotType
let description: String
let onTap: (ScreenshotSnippingTool.ScreenshotType) -> Void
var body: some View {
Button(action: { onTap(type) }) {
HStack(spacing: 12) {
Image(systemName: type.iconName)
.foregroundColor(.blue)
.font(.system(size: 16))
.frame(width: 20, alignment: .center)
VStack(alignment: .leading, spacing: 2) {
Text(type.displayName)
.font(.system(size: 14, weight: .medium))
.foregroundColor(.primary)
Text(description)
.font(.system(size: 12))
.foregroundColor(.secondary)
}
Spacer()
}
.padding(.horizontal, 8)
.padding(.vertical, 6)
.background(
RoundedRectangle(cornerRadius: 6)
.fill(Color.clear)
.contentShape(Rectangle())
)
.overlay(
RoundedRectangle(cornerRadius: 6)
.stroke(Color.clear, lineWidth: 1)
)
}
.buttonStyle(PlainButtonStyle())
.background(
RoundedRectangle(cornerRadius: 6)
.fill(Color(NSColor.controlBackgroundColor))
.opacity(0.5)
)
.onHover { isHovered in
// Add subtle hover effect if needed
}
}
}
// MARK: - Screenshot Popover Background (Hidden from Screen Recording)
struct ScreenshotPopoverBackground: NSViewRepresentable {
func makeNSView(context: Context) -> NSView {
let view = NSView()
// Apply screen capture protection like our other panels
DispatchQueue.main.async {
if let window = view.window {
self.updateScreenCaptureVisibility(window: window)
self.setupScreenCaptureObserver(window: window)
}
}
return view
}
func updateNSView(_ nsView: NSView, context: Context) {
// Update screen capture protection when view updates
if let window = nsView.window {
updateScreenCaptureVisibility(window: window)
}
}
private func updateScreenCaptureVisibility(window: NSWindow) {
let shouldHide = Defaults[.hidePanelsFromScreenCapture]
if shouldHide {
// Hide from screen capture and recording
window.sharingType = .none
print("🙈 ScreenshotPopover: Hidden from screen capture and recordings")
} else {
// Allow normal screen capture
window.sharingType = .readOnly
print("👁️ ScreenshotPopover: Visible in screen capture and recordings")
}
}
private func setupScreenCaptureObserver(window: NSWindow) {
// Observe changes to hidePanelsFromScreenCapture setting
Defaults.observe(.hidePanelsFromScreenCapture) { [weak window] change in
DispatchQueue.main.async {
guard let window = window else { return }
self.updateScreenCaptureVisibility(window: window)
}
}
}
}