Files
openless/Sources/OpenLessApp/Settings/SettingsView.swift
T
baiqing 22a9885d44 feat(settings): unified 配置 Tab + add new ASR presets
- 合并 LLM Provider Tab 与 ASR Provider Tab 到同一个「配置」页:
  顶部 LLM 模型 chip 行 + 表单,下方 ASR 语音 chip 行 + provider 专属字段,
  底部 borderedProminent .large「保存」按钮统一提交。
- 切 chip 不再立即写盘——所有改动在内存草稿里积攒,点保存才写 vault / UserDefaults
  并 post .openLessCredentialsChanged。
- 火山引擎 3 字段(APP ID / Access Token / Resource ID)从 SettingsHubTab 搬到
  「配置」页 ASR 段;SettingsHubTab 简化为录音快捷键 / 授权 / 隐私 / 关于 + provider 概览。
- 侧边栏顺序调整为 首页 → 历史记录 → 词汇表 → 风格 → 配置 → 设置 → 帮助中心,
  「配置」紧靠「设置」之上。
- ASRProviderRegistry 新增两条预设:
  * aliyun-paraformer (DashScope 流式 paraformer-realtime-v2)
  * custom-openai-whisper (OpenAI 兼容批量 Whisper API)
  这两类 provider 的 chip 与表单已就绪;运行期具体识别由并行分支补齐。
- 删除 LLMProvidersTab.swift / ASRProvidersTab.swift;AddLLMProviderSheet 搬到
  ProvidersConfigTab.swift 同文件。
2026-04-29 13:02:58 +08:00

92 lines
2.8 KiB
Swift

import AppKit
import SwiftUI
import OpenLessCore
import OpenLessHotkey
import OpenLessPersistence
import OpenLessRecorder
import OpenLessASR
import OpenLessPolish
// 设置窗口的根入口:导航枚举 + 模型 + 主分发。
// 共享组件、侧边栏、各 Tab、遗留 Tab、通知名都在同目录其他文件里。
enum OpenLessMainTab: String, CaseIterable, Identifiable {
case home
case history
case dictionary
case polish
case providersConfig
case settings
case help
var id: String { rawValue }
var title: String {
switch self {
case .home: return "首页"
case .history: return "历史记录"
case .dictionary: return "词汇表"
case .polish: return "风格"
case .providersConfig: return "配置"
case .settings: return "设置"
case .help: return "帮助中心"
}
}
var symbol: String {
switch self {
case .home: return "chart.line.uptrend.xyaxis"
case .history: return "clock"
case .dictionary: return "text.book.closed"
case .polish: return "paintpalette"
case .providersConfig: return "slider.horizontal.3"
case .settings: return "gearshape"
case .help: return "questionmark.circle"
}
}
}
@MainActor
final class SettingsNavigationModel: ObservableObject {
@Published var selection: OpenLessMainTab
init(selection: OpenLessMainTab = .home) {
self.selection = selection
}
}
struct SettingsView: View {
@ObservedObject private var navigation: SettingsNavigationModel
init(navigation: SettingsNavigationModel) {
self.navigation = navigation
}
var body: some View {
HStack(spacing: 14) {
FixedSidebar(selection: $navigation.selection)
Group {
switch navigation.selection {
case .home: HomeTab()
case .history: HistoryTab()
case .dictionary: DictionaryTab()
case .polish: StyleTab()
case .providersConfig: ProvidersConfigTab()
case .settings: SettingsHubTab()
case .help: HelpTab()
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
// 右栏顶部留点空白,避免内容贴到 title bar 区域。
.padding(.top, 12)
}
// 左/下/右用相等 12pt;上方为 0,让侧边栏顶边贴窗口顶,
// 红绿灯(系统画在 title bar 层)就自然落在侧边栏的圆角矩形内部。
.padding(.leading, 12)
.padding(.trailing, 12)
.padding(.bottom, 12)
.background(WindowCanvasBackground())
.frame(minWidth: 1040, minHeight: 700)
}
}