mirror of
https://github.com/carey314/mio-plugin-clipper.git
synced 2026-08-10 07:44:32 +00:00
166 lines
6.8 KiB
Swift
166 lines
6.8 KiB
Swift
|
|
//
|
|||
|
|
// PermissionBanner.swift
|
|||
|
|
// 划词侠 plugin
|
|||
|
|
//
|
|||
|
|
// Two banners share this file:
|
|||
|
|
// • Accessibility-permission warning (when sourceMode = .selection)
|
|||
|
|
// • Missing-config (state E) full-card with copy-path helper
|
|||
|
|
//
|
|||
|
|
|
|||
|
|
import SwiftUI
|
|||
|
|
|
|||
|
|
struct AccessibilityBanner: View {
|
|||
|
|
var onOpenSettings: () -> Void
|
|||
|
|
|
|||
|
|
var body: some View {
|
|||
|
|
HStack(alignment: .top, spacing: 8) {
|
|||
|
|
Image(systemName: "exclamationmark.triangle.fill")
|
|||
|
|
.foregroundColor(ClipperTheme.amber)
|
|||
|
|
.font(.system(size: 12))
|
|||
|
|
.padding(.top, 1)
|
|||
|
|
VStack(alignment: .leading, spacing: 4) {
|
|||
|
|
Text("选中文本需要辅助功能权限")
|
|||
|
|
.font(.system(size: 11.5, weight: .semibold))
|
|||
|
|
.foregroundColor(ClipperTheme.fg85)
|
|||
|
|
Text("前往 系统设置 > 隐私与安全性 > 辅助功能,勾选 Mio Island 后回来重试。当前已自动回退到粘贴板。")
|
|||
|
|
.font(.system(size: 10.5))
|
|||
|
|
.foregroundColor(ClipperTheme.fg55)
|
|||
|
|
.fixedSize(horizontal: false, vertical: true)
|
|||
|
|
Button(action: onOpenSettings) {
|
|||
|
|
Text("打开 系统设置")
|
|||
|
|
.font(.system(size: 11, weight: .semibold))
|
|||
|
|
.foregroundColor(ClipperTheme.amber)
|
|||
|
|
}
|
|||
|
|
.buttonStyle(.plain)
|
|||
|
|
.padding(.top, 2)
|
|||
|
|
}
|
|||
|
|
Spacer(minLength: 0)
|
|||
|
|
}
|
|||
|
|
.padding(10)
|
|||
|
|
.background(
|
|||
|
|
RoundedRectangle(cornerRadius: 10)
|
|||
|
|
.fill(ClipperTheme.amber.opacity(0.08))
|
|||
|
|
.overlay(
|
|||
|
|
RoundedRectangle(cornerRadius: 10)
|
|||
|
|
.stroke(ClipperTheme.amber.opacity(0.25), lineWidth: 0.5)
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
struct MissingConfigCard: View {
|
|||
|
|
@ObservedObject var store: ClipperStore
|
|||
|
|
@State private var copied = false
|
|||
|
|
|
|||
|
|
var body: some View {
|
|||
|
|
VStack(alignment: .leading, spacing: 12) {
|
|||
|
|
HStack(spacing: 8) {
|
|||
|
|
Image(systemName: "key.horizontal")
|
|||
|
|
.font(.system(size: 14, weight: .semibold))
|
|||
|
|
.foregroundColor(ClipperTheme.amber)
|
|||
|
|
Text("先填一个 DeepSeek API Key")
|
|||
|
|
.font(.system(size: 13, weight: .semibold))
|
|||
|
|
.foregroundColor(ClipperTheme.fgPrimary)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
VStack(alignment: .leading, spacing: 6) {
|
|||
|
|
Text("打开下面的配置文件,把 deepseek_api_key 改成你的真实 key,然后点 重新加载。")
|
|||
|
|
.font(.system(size: 11.5))
|
|||
|
|
.foregroundColor(ClipperTheme.fg70)
|
|||
|
|
.fixedSize(horizontal: false, vertical: true)
|
|||
|
|
|
|||
|
|
Text(ClipperConfig.configPath)
|
|||
|
|
.font(.system(size: 10.5, design: .monospaced))
|
|||
|
|
.foregroundColor(ClipperTheme.fg55)
|
|||
|
|
.padding(.horizontal, 10)
|
|||
|
|
.padding(.vertical, 8)
|
|||
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|||
|
|
.background(
|
|||
|
|
RoundedRectangle(cornerRadius: 8)
|
|||
|
|
.fill(ClipperTheme.overlay04)
|
|||
|
|
.overlay(
|
|||
|
|
RoundedRectangle(cornerRadius: 8)
|
|||
|
|
.stroke(ClipperTheme.overlay08, lineWidth: 0.5)
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
.textSelection(.enabled)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
HStack(spacing: 8) {
|
|||
|
|
Button {
|
|||
|
|
store.copyToPasteboard(ClipperConfig.configPath)
|
|||
|
|
copied = true
|
|||
|
|
Task {
|
|||
|
|
try? await Task.sleep(nanoseconds: 1_200_000_000)
|
|||
|
|
await MainActor.run { copied = false }
|
|||
|
|
}
|
|||
|
|
} label: {
|
|||
|
|
HStack(spacing: 6) {
|
|||
|
|
Image(systemName: copied ? "checkmark" : "doc.on.doc")
|
|||
|
|
.font(.system(size: 11, weight: .semibold))
|
|||
|
|
Text(copied ? "路径已复制" : "复制路径")
|
|||
|
|
.font(.system(size: 12, weight: .semibold))
|
|||
|
|
}
|
|||
|
|
.foregroundColor(copied ? ClipperTheme.lime : ClipperTheme.fg70)
|
|||
|
|
.frame(maxWidth: .infinity)
|
|||
|
|
.frame(height: 30)
|
|||
|
|
.background(
|
|||
|
|
Capsule().fill(ClipperTheme.overlay06)
|
|||
|
|
.overlay(Capsule().stroke(ClipperTheme.overlay08, lineWidth: 0.5))
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
.buttonStyle(.plain)
|
|||
|
|
|
|||
|
|
Button {
|
|||
|
|
NSWorkspace.shared.open(URL(fileURLWithPath: ClipperConfig.configDir))
|
|||
|
|
} label: {
|
|||
|
|
HStack(spacing: 6) {
|
|||
|
|
Image(systemName: "folder")
|
|||
|
|
.font(.system(size: 11, weight: .semibold))
|
|||
|
|
Text("打开文件夹")
|
|||
|
|
.font(.system(size: 12, weight: .semibold))
|
|||
|
|
}
|
|||
|
|
.foregroundColor(ClipperTheme.fg70)
|
|||
|
|
.frame(maxWidth: .infinity)
|
|||
|
|
.frame(height: 30)
|
|||
|
|
.background(
|
|||
|
|
Capsule().fill(ClipperTheme.overlay06)
|
|||
|
|
.overlay(Capsule().stroke(ClipperTheme.overlay08, lineWidth: 0.5))
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
.buttonStyle(.plain)
|
|||
|
|
|
|||
|
|
Button {
|
|||
|
|
store.reloadConfig()
|
|||
|
|
} label: {
|
|||
|
|
HStack(spacing: 6) {
|
|||
|
|
Image(systemName: "arrow.clockwise")
|
|||
|
|
.font(.system(size: 11, weight: .semibold))
|
|||
|
|
Text("重新加载")
|
|||
|
|
.font(.system(size: 12, weight: .semibold))
|
|||
|
|
}
|
|||
|
|
.foregroundColor(Color(red: 0x0B/255, green: 0x0B/255, blue: 0x0B/255))
|
|||
|
|
.frame(maxWidth: .infinity)
|
|||
|
|
.frame(height: 30)
|
|||
|
|
.background(Capsule().fill(ClipperTheme.lime))
|
|||
|
|
}
|
|||
|
|
.buttonStyle(.plain)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Text("没有 key?去 platform.deepseek.com 注册一个,新用户有免费额度。")
|
|||
|
|
.font(.system(size: 10.5))
|
|||
|
|
.foregroundColor(ClipperTheme.fg45)
|
|||
|
|
}
|
|||
|
|
.padding(14)
|
|||
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|||
|
|
.background(
|
|||
|
|
RoundedRectangle(cornerRadius: 14)
|
|||
|
|
.fill(ClipperTheme.overlay04)
|
|||
|
|
.overlay(
|
|||
|
|
RoundedRectangle(cornerRadius: 14)
|
|||
|
|
.stroke(ClipperTheme.overlay08, lineWidth: 0.5)
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
}
|