Complete Phase 4: Comprehensive preferences, localization, and UX polish

- Rename application from MenuWhisper to Tell me with new domain com.fmartingr.tellme
- Implement comprehensive preferences window with 6 tabs (General, Models, Text Insertion, Interface, Advanced, Permissions)
- Add full English/Spanish localization for all UI elements
- Create functional onboarding flow with model download capability
- Implement preview dialog for transcription editing
- Add settings export/import functionality
- Fix HUD content display issues and add comprehensive permission checking
- Enhance build scripts and app bundle creation for proper localization support
This commit is contained in:
Felipe M 2025-09-19 13:55:46 +02:00
parent 7ba5895406
commit 54c3b65d4a
Signed by: fmartingr
GPG key ID: CCFBC5637D4000A8
25 changed files with 3086 additions and 235 deletions

View file

@ -1,6 +1,7 @@
import SwiftUI
import AppKit
import CoreUtils
import CoreSettings
public enum HUDState {
case hidden
@ -8,12 +9,21 @@ public enum HUDState {
case processing
}
public class HUDWindow: NSPanel {
public class HUDWindow: NSPanel, ObservableObject {
private var hostingView: NSHostingView<HUDContentView>?
private let settings: CoreSettings.Settings
@Published var hudState: HUDState = .hidden
public init(settings: CoreSettings.Settings) {
self.settings = settings
let baseWidth: CGFloat = 320
let baseHeight: CGFloat = 160
let scaledWidth = baseWidth * settings.hudSize
let scaledHeight = baseHeight * settings.hudSize
public init() {
super.init(
contentRect: NSRect(x: 0, y: 0, width: 320, height: 160),
contentRect: NSRect(x: 0, y: 0, width: scaledWidth, height: scaledHeight),
styleMask: [.nonactivatingPanel],
backing: .buffered,
defer: false
@ -33,7 +43,7 @@ public class HUDWindow: NSPanel {
}
private func setupContentView() {
let hudContentView = HUDContentView()
let hudContentView = HUDContentView(settings: settings, hudWindow: self)
hostingView = NSHostingView(rootView: hudContentView)
if let hostingView = hostingView {
@ -44,16 +54,16 @@ public class HUDWindow: NSPanel {
public func show(state: HUDState) {
centerOnScreen()
if let hostingView = hostingView {
hostingView.rootView.updateState(state)
}
// Update the published state
hudState = state
print("HUD showing with state: \(state)")
if !isVisible {
orderFront(nil)
alphaValue = 0
NSAnimationContext.runAnimationGroup({ context in
context.duration = 0.2
animator().alphaValue = 1.0
animator().alphaValue = settings.hudOpacity
})
}
}
@ -70,9 +80,7 @@ public class HUDWindow: NSPanel {
}
public func updateLevel(_ level: Float) {
if let hostingView = hostingView {
hostingView.rootView.updateState(.listening(level: level))
}
hudState = .listening(level: level)
}
private func centerOnScreen() {
@ -105,7 +113,8 @@ extension Notification.Name {
}
struct HUDContentView: View {
@State private var currentState: HUDState = .hidden
@ObservedObject var settings: CoreSettings.Settings
@ObservedObject var hudWindow: HUDWindow
var body: some View {
ZStack {
@ -117,7 +126,7 @@ struct HUDContentView: View {
)
VStack(spacing: 16) {
switch currentState {
switch hudWindow.hudState {
case .hidden:
EmptyView()
@ -130,7 +139,11 @@ struct HUDContentView: View {
}
.padding(24)
}
.frame(width: 320, height: 160)
.frame(width: 320 * settings.hudSize, height: 160 * settings.hudSize)
.scaleEffect(settings.hudSize)
.onAppear {
print("HUD Content View appeared with state: \(hudWindow.hudState)")
}
}
@ViewBuilder
@ -140,14 +153,14 @@ struct HUDContentView: View {
.font(.system(size: 32))
.foregroundColor(.blue)
Text("Listening...")
Text(NSLocalizedString("hud.listening", comment: "Listening..."))
.font(.headline)
.foregroundColor(.primary)
AudioLevelView(level: level)
.frame(height: 20)
Text("Press Esc to cancel")
Text(NSLocalizedString("hud.cancel", comment: "Press Esc to cancel"))
.font(.caption)
.foregroundColor(.secondary)
}
@ -159,21 +172,16 @@ struct HUDContentView: View {
ProgressView()
.scaleEffect(1.2)
Text("Processing...")
Text(NSLocalizedString("hud.processing", comment: "Processing..."))
.font(.headline)
.foregroundColor(.primary)
Text("Please wait")
Text(NSLocalizedString("hud.please_wait", comment: "Please wait"))
.font(.caption)
.foregroundColor(.secondary)
}
}
func updateState(_ state: HUDState) {
withAnimation(.easeInOut(duration: 0.3)) {
currentState = state
}
}
}
struct AudioLevelView: View {