VoiceInput/Sources/Core/NotchDisplayManager.swift
JOJO c708ff32ac feat: Ask AI 刘海弹窗输出模式
- 新增 AssistOutputMode 配置(inject/notch)
- Assist 设置界面添加输出方式弹出菜单
- 新建 NotchDisplayManager:DynamicNotchKit 弹窗,支持滚动、复制、15s 自动消失
- DynamicNotchKit 固化为本地依赖,修复假刘海高度问题(0→内容贴近顶部)
2026-04-28 23:18:13 +08:00

97 lines
2.7 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Cocoa
import SwiftUI
import DynamicNotchKit
/// AI
final class NotchDisplayManager {
static let shared = NotchDisplayManager()
private var currentNotch: DynamicNotch<NotchContentView>?
private var isActive = false
private init() {}
/// / AI
func show(text: String) {
currentNotch?.hide()
let content = NotchContentView(
text: text,
onCopy: {
let pasteboard = NSPasteboard.general
pasteboard.clearContents()
pasteboard.setString(text, forType: .string)
}
)
currentNotch = DynamicNotch(style: .notch) {
content
}
isActive = true
// 15
currentNotch?.show(for: 15)
}
func hide() {
currentNotch?.hide()
currentNotch = nil
isActive = false
}
}
// MARK: -
struct NotchContentView: View {
let text: String
var onCopy: () -> Void
private let maxHeight: CGFloat = 220
var body: some View {
VStack(alignment: .leading, spacing: 8) {
//
HStack(spacing: 0) {
HStack(spacing: 4) {
Image(systemName: "sparkles")
.font(.system(size: 10))
Text("AI 助手回复")
.font(.system(size: 11, weight: .medium))
}
.foregroundColor(.white.opacity(0.5))
Spacer()
Button(action: onCopy) {
HStack(spacing: 3) {
Image(systemName: "doc.on.doc")
.font(.system(size: 9))
Text("复制")
.font(.system(size: 10))
}
.foregroundColor(.white.opacity(0.8))
.padding(.horizontal, 8)
.padding(.vertical, 3)
.background(.white.opacity(0.12))
.clipShape(Capsule())
}
.buttonStyle(.plain)
}
//
ScrollView(.vertical, showsIndicators: false) {
Text(text)
.font(.system(size: 13))
.foregroundColor(.white.opacity(0.85))
.lineSpacing(4)
.frame(maxWidth: .infinity, alignment: .leading)
}
.frame(maxHeight: maxHeight)
}
.padding(.horizontal, 14)
.padding(.vertical, 10)
.frame(width: 320)
}
}