feat(translation-polish): dual-engine translation UX + provider picker filter + topbar cleanup

- Add LLMProvider.isUserSelectable (default true) and filter
  ProviderPickerSection on it; next pass can hide non-user presets
  (e.g. a future DeepSeek key-preset) without changing call sites.
- KeyboardRootView: hide TranslationChip when off (matches user's
  mental model of an opt-in feature), drop the 'warming' branch
  (Qwen3 download UX was removed with the backend in v0.2.0), unify
  chip pill height to minHeight 28 + vertical 6 for visual rhythm
  across all topbar chips.
- TranslationChip: drop isLocal warning path — both engines now
  run the translate-and-polish step (local routes through DeepSeek
  via ProviderConfig.localModeProviderId).
- OnboardingView: cloud engine branch now wraps the translation
  row in the same surface card chrome as the local branch.
- Strings: drop keyboard.models.warming (no longer referenced).

DeepSeek key pre-fill deferred to a follow-up.
This commit is contained in:
2026-06-25 15:16:04 +08:00
parent 0956bb8534
commit 93b6aa6c02
7 changed files with 46 additions and 43 deletions
+9 -1
View File
@@ -14,6 +14,12 @@ public struct LLMProvider: Identifiable, Codable, Hashable, Sendable {
public let apiKeyURL: URL?
/// Optional short blurb shown under the provider name in the picker.
public let blurb: String?
/// Whether this preset should appear in user-facing provider pickers
/// (settings / onboarding). Defaults to `true` so the existing
/// `presets` array keeps its public surface area; future passes can
/// mark e.g. a DeepSeek key-pre-fill preset as `false` to hide it
/// from the picker without touching call sites.
public let isUserSelectable: Bool
public init(
id: String,
@@ -21,7 +27,8 @@ public struct LLMProvider: Identifiable, Codable, Hashable, Sendable {
defaultBaseURL: String,
defaultModel: String,
apiKeyURL: URL? = nil,
blurb: String? = nil
blurb: String? = nil,
isUserSelectable: Bool = true
) {
self.id = id
self.name = name
@@ -29,6 +36,7 @@ public struct LLMProvider: Identifiable, Codable, Hashable, Sendable {
self.defaultModel = defaultModel
self.apiKeyURL = apiKeyURL
self.blurb = blurb
self.isUserSelectable = isUserSelectable
}
public static let presets: [LLMProvider] = [