[JJC-20260618-005-C-2] Refactor: replace 166 Palette.xxx with @Environment(\.themePalette) (ARCH-A2)
This commit is contained in:
@@ -22,6 +22,7 @@ import SwiftUI
|
||||
import OSGKeyboardShared
|
||||
|
||||
public struct KeyboardRootView: View {
|
||||
@Environment(\.themePalette) private var palette: ThemePalette
|
||||
|
||||
@ObservedObject var state: State
|
||||
|
||||
@@ -69,7 +70,7 @@ public struct KeyboardRootView: View {
|
||||
}
|
||||
.overlay(alignment: .top) {
|
||||
Rectangle()
|
||||
.fill(Palette.divider)
|
||||
.fill(palette.divider)
|
||||
.frame(height: 0.5)
|
||||
}
|
||||
}
|
||||
@@ -89,10 +90,10 @@ public struct KeyboardRootView: View {
|
||||
Button(action: state.openSettings) {
|
||||
Image(systemName: "gearshape.fill")
|
||||
.font(.system(size: 13, weight: .medium))
|
||||
.foregroundStyle(Palette.textSecondary)
|
||||
.foregroundStyle(palette.textSecondary)
|
||||
.frame(width: 28, height: 28)
|
||||
.background(Palette.surface, in: Circle())
|
||||
.overlay(Circle().stroke(Palette.divider, lineWidth: 0.5))
|
||||
.background(palette.surface, in: Circle())
|
||||
.overlay(Circle().stroke(palette.divider, lineWidth: 0.5))
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityLabel(Text("Open OSGKeyboard settings"))
|
||||
@@ -134,12 +135,12 @@ public struct KeyboardRootView: View {
|
||||
Button(action: state.insertSpace) {
|
||||
Text("空格")
|
||||
.font(TypeStyle.body)
|
||||
.foregroundStyle(Palette.textPrimary)
|
||||
.foregroundStyle(palette.textPrimary)
|
||||
.frame(maxWidth: .infinity, minHeight: 42)
|
||||
.background(Palette.surfaceElevated, in: RoundedRectangle(cornerRadius: Radius.medium, style: .continuous))
|
||||
.background(palette.surfaceElevated, in: RoundedRectangle(cornerRadius: Radius.medium, style: .continuous))
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: Radius.medium, style: .continuous)
|
||||
.stroke(Palette.divider, lineWidth: 0.5)
|
||||
.stroke(palette.divider, lineWidth: 0.5)
|
||||
)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
@@ -195,6 +196,8 @@ extension KeyboardRootView {
|
||||
// MARK: - Transcript line
|
||||
|
||||
private struct TranscriptLine: View {
|
||||
@Environment(\.themePalette) private var palette: ThemePalette
|
||||
|
||||
let phase: KeyboardViewController.State.Phase
|
||||
let transcript: String
|
||||
|
||||
@@ -204,38 +207,38 @@ private struct TranscriptLine: View {
|
||||
case .idle:
|
||||
Text("按住说话 · Hold to talk")
|
||||
.font(TypeStyle.caption)
|
||||
.foregroundStyle(Palette.textTertiary)
|
||||
.foregroundStyle(palette.textTertiary)
|
||||
case .requestingPermissions:
|
||||
HStack(spacing: 6) {
|
||||
ProgressView().controlSize(.mini).tint(Palette.textSecondary)
|
||||
ProgressView().controlSize(.mini).tint(palette.textSecondary)
|
||||
Text("准备中…")
|
||||
.font(TypeStyle.caption)
|
||||
.foregroundStyle(Palette.textSecondary)
|
||||
.foregroundStyle(palette.textSecondary)
|
||||
}
|
||||
case .recording:
|
||||
Text(transcript.isEmpty ? " " : transcript)
|
||||
.font(TypeStyle.caption)
|
||||
.foregroundStyle(Palette.textPrimary)
|
||||
.foregroundStyle(palette.textPrimary)
|
||||
.lineLimit(1)
|
||||
.truncationMode(.head)
|
||||
.frame(maxWidth: .infinity)
|
||||
case .processing:
|
||||
HStack(spacing: 6) {
|
||||
ProgressView().controlSize(.mini).tint(Palette.accent)
|
||||
ProgressView().controlSize(.mini).tint(palette.accent)
|
||||
Text("润色中 · Polishing")
|
||||
.font(TypeStyle.caption)
|
||||
.foregroundStyle(Palette.textSecondary)
|
||||
.foregroundStyle(palette.textSecondary)
|
||||
}
|
||||
case .error(let msg):
|
||||
Text(msg)
|
||||
.font(TypeStyle.caption)
|
||||
.foregroundStyle(Palette.warning)
|
||||
.foregroundStyle(palette.warning)
|
||||
.lineLimit(1)
|
||||
.truncationMode(.tail)
|
||||
case .denied(let reason):
|
||||
Text(deniedMessage(for: reason))
|
||||
.font(TypeStyle.caption)
|
||||
.foregroundStyle(Palette.warning)
|
||||
.foregroundStyle(palette.warning)
|
||||
.lineLimit(1)
|
||||
.truncationMode(.tail)
|
||||
}
|
||||
@@ -255,6 +258,8 @@ private struct TranscriptLine: View {
|
||||
// MARK: - Toolbar icon button
|
||||
|
||||
private struct ToolbarIconButton: View {
|
||||
@Environment(\.themePalette) private var palette: ThemePalette
|
||||
|
||||
let systemName: String
|
||||
let label: String
|
||||
let action: () -> Void
|
||||
@@ -263,12 +268,12 @@ private struct ToolbarIconButton: View {
|
||||
Button(action: action) {
|
||||
Image(systemName: systemName)
|
||||
.font(.system(size: 16, weight: .medium))
|
||||
.foregroundStyle(Palette.textPrimary)
|
||||
.foregroundStyle(palette.textPrimary)
|
||||
.frame(width: 40, height: 40)
|
||||
.background(Palette.surfaceElevated, in: RoundedRectangle(cornerRadius: Radius.medium, style: .continuous))
|
||||
.background(palette.surfaceElevated, in: RoundedRectangle(cornerRadius: Radius.medium, style: .continuous))
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: Radius.medium, style: .continuous)
|
||||
.stroke(Palette.divider, lineWidth: 0.5)
|
||||
.stroke(palette.divider, lineWidth: 0.5)
|
||||
)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
@@ -279,6 +284,8 @@ private struct ToolbarIconButton: View {
|
||||
// MARK: - Status badge
|
||||
|
||||
private struct StatusBadge: View {
|
||||
@Environment(\.themePalette) private var palette: ThemePalette
|
||||
|
||||
let phase: KeyboardViewController.State.Phase
|
||||
|
||||
var body: some View {
|
||||
@@ -289,13 +296,13 @@ private struct StatusBadge: View {
|
||||
case .requestingPermissions:
|
||||
EmptyView()
|
||||
case .recording:
|
||||
dot(color: Palette.recordRed, label: "REC")
|
||||
dot(color: palette.recordRed, label: "REC")
|
||||
case .processing:
|
||||
dot(color: Palette.accent, label: "···")
|
||||
dot(color: palette.accent, label: "···")
|
||||
case .error:
|
||||
dot(color: Palette.warning, label: "!")
|
||||
dot(color: palette.warning, label: "!")
|
||||
case .denied:
|
||||
dot(color: Palette.warning, label: "!")
|
||||
dot(color: palette.warning, label: "!")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -307,18 +314,20 @@ private struct StatusBadge: View {
|
||||
.frame(width: 6, height: 6)
|
||||
Text(label)
|
||||
.font(TypeStyle.caption2)
|
||||
.foregroundStyle(Palette.textSecondary)
|
||||
.foregroundStyle(palette.textSecondary)
|
||||
}
|
||||
.padding(.horizontal, Spacing.xs)
|
||||
.padding(.vertical, 3)
|
||||
.background(Palette.surface, in: Capsule())
|
||||
.overlay(Capsule().stroke(Palette.divider, lineWidth: 0.5))
|
||||
.background(palette.surface, in: Capsule())
|
||||
.overlay(Capsule().stroke(palette.divider, lineWidth: 0.5))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Mode chip
|
||||
|
||||
private struct ModeChip: View {
|
||||
@Environment(\.themePalette) private var palette: ThemePalette
|
||||
|
||||
let mode: KeyboardViewController.State.InputMode
|
||||
let onChange: (KeyboardViewController.State.InputMode) -> Void
|
||||
|
||||
@@ -343,11 +352,11 @@ private struct ModeChip: View {
|
||||
.font(.system(size: 8, weight: .bold))
|
||||
}
|
||||
.font(TypeStyle.caption2)
|
||||
.foregroundStyle(mode == .off ? Palette.textTertiary : Palette.textPrimary)
|
||||
.foregroundStyle(mode == .off ? palette.textTertiary : palette.textPrimary)
|
||||
.padding(.horizontal, Spacing.xs + 2)
|
||||
.padding(.vertical, 4)
|
||||
.background(Palette.surfaceElevated, in: Capsule())
|
||||
.overlay(Capsule().stroke(Palette.divider, lineWidth: 0.5))
|
||||
.background(palette.surfaceElevated, in: Capsule())
|
||||
.overlay(Capsule().stroke(palette.divider, lineWidth: 0.5))
|
||||
}
|
||||
.menuStyle(.button)
|
||||
}
|
||||
@@ -372,6 +381,8 @@ private struct ModeChip: View {
|
||||
// MARK: - Locale chip
|
||||
|
||||
private struct LocaleChip: View {
|
||||
@Environment(\.themePalette) private var palette: ThemePalette
|
||||
|
||||
let localeId: String
|
||||
let onChange: (String) -> Void
|
||||
|
||||
@@ -405,11 +416,11 @@ private struct LocaleChip: View {
|
||||
.font(.system(size: 8, weight: .bold))
|
||||
}
|
||||
.font(TypeStyle.caption2)
|
||||
.foregroundStyle(Palette.textPrimary)
|
||||
.foregroundStyle(palette.textPrimary)
|
||||
.padding(.horizontal, Spacing.xs + 2)
|
||||
.padding(.vertical, 4)
|
||||
.background(Palette.surfaceElevated, in: Capsule())
|
||||
.overlay(Capsule().stroke(Palette.divider, lineWidth: 0.5))
|
||||
.background(palette.surfaceElevated, in: Capsule())
|
||||
.overlay(Capsule().stroke(palette.divider, lineWidth: 0.5))
|
||||
}
|
||||
.menuStyle(.button)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import SwiftUI
|
||||
import OSGKeyboardShared
|
||||
|
||||
struct RecordButton: View {
|
||||
@Environment(\.themePalette) private var palette: ThemePalette
|
||||
|
||||
enum Phase: Equatable {
|
||||
case idle
|
||||
case recording
|
||||
@@ -44,7 +46,7 @@ struct RecordButton: View {
|
||||
ZStack {
|
||||
// Outer breathing ring (recording only)
|
||||
Circle()
|
||||
.stroke(Palette.recordRed.opacity(0.35), lineWidth: 2)
|
||||
.stroke(palette.recordRed.opacity(0.35), lineWidth: 2)
|
||||
.frame(width: 150, height: 150)
|
||||
.scaleEffect(breath ? 1.18 : 0.95)
|
||||
.opacity(phase == .recording ? 1 : 0)
|
||||
@@ -54,7 +56,7 @@ struct RecordButton: View {
|
||||
Circle()
|
||||
.fill(
|
||||
RadialGradient(
|
||||
colors: [Palette.recordRed.opacity(0.55), .clear],
|
||||
colors: [palette.recordRed.opacity(0.55), .clear],
|
||||
center: .center,
|
||||
startRadius: 50,
|
||||
endRadius: 100
|
||||
@@ -88,7 +90,7 @@ struct RecordButton: View {
|
||||
case .idle:
|
||||
Image(systemName: "mic.fill")
|
||||
.font(.system(size: 38, weight: .medium))
|
||||
.foregroundStyle(Palette.textPrimary)
|
||||
.foregroundStyle(palette.textPrimary)
|
||||
case .recording:
|
||||
WaveformView(level: level, active: true)
|
||||
.frame(width: 80, height: 44)
|
||||
@@ -96,12 +98,12 @@ struct RecordButton: View {
|
||||
case .processing:
|
||||
ProgressView()
|
||||
.progressViewStyle(.circular)
|
||||
.tint(Palette.textPrimary)
|
||||
.tint(palette.textPrimary)
|
||||
.scaleEffect(1.2)
|
||||
case .error:
|
||||
Image(systemName: "exclamationmark.triangle.fill")
|
||||
.font(.system(size: 30, weight: .medium))
|
||||
.foregroundStyle(Palette.warning)
|
||||
.foregroundStyle(palette.warning)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,19 +162,19 @@ struct RecordButton: View {
|
||||
switch phase {
|
||||
case .recording:
|
||||
return LinearGradient(
|
||||
colors: [Palette.recordRed.opacity(0.95), Palette.recordRed.opacity(0.75)],
|
||||
colors: [palette.recordRed.opacity(0.95), palette.recordRed.opacity(0.75)],
|
||||
startPoint: .top,
|
||||
endPoint: .bottom
|
||||
)
|
||||
case .processing:
|
||||
return LinearGradient(
|
||||
colors: [Palette.surfaceElevated, Palette.surface],
|
||||
colors: [palette.surfaceElevated, palette.surface],
|
||||
startPoint: .top,
|
||||
endPoint: .bottom
|
||||
)
|
||||
case .error:
|
||||
return LinearGradient(
|
||||
colors: [Palette.warning.opacity(0.85), Palette.warning.opacity(0.55)],
|
||||
colors: [palette.warning.opacity(0.85), palette.warning.opacity(0.55)],
|
||||
startPoint: .top,
|
||||
endPoint: .bottom
|
||||
)
|
||||
|
||||
@@ -10,15 +10,17 @@ import SwiftUI
|
||||
import OSGKeyboardShared
|
||||
|
||||
struct WaveformView: View {
|
||||
@Environment(\.themePalette) private var palette: ThemePalette
|
||||
|
||||
let level: Double // 0...1, smoothed RMS
|
||||
let barCount: Int
|
||||
let color: Color
|
||||
let color: Color?
|
||||
let active: Bool // when false, bars collapse to a thin resting line
|
||||
|
||||
init(
|
||||
level: Double,
|
||||
barCount: Int = 18,
|
||||
color: Color = Palette.recordRed,
|
||||
color: Color? = nil,
|
||||
active: Bool = true
|
||||
) {
|
||||
self.level = max(0, min(1, level))
|
||||
@@ -27,12 +29,16 @@ struct WaveformView: View {
|
||||
self.active = active
|
||||
}
|
||||
|
||||
private var resolvedColor: Color {
|
||||
color ?? palette.recordRed
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
TimelineView(.animation(minimumInterval: 1.0 / 30.0)) { context in
|
||||
HStack(alignment: .center, spacing: 3) {
|
||||
ForEach(0..<barCount, id: \.self) { i in
|
||||
Capsule()
|
||||
.fill(color)
|
||||
.fill(resolvedColor)
|
||||
.frame(width: 2.4, height: height(for: i, time: context.date.timeIntervalSinceReferenceDate))
|
||||
.opacity(active ? 1.0 : 0.45)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user