Skip to content

Bugs and UI Fixes - #7

Merged
karansinghgit merged 5 commits into
mainfrom
ormversion
Jan 18, 2026
Merged

Bugs and UI Fixes #7
karansinghgit merged 5 commits into
mainfrom
ormversion

Conversation

@iamtheorm

Copy link
Copy Markdown
Collaborator

UI Overhaul and Stability Improvements for SpeakType

Summary

This PR delivers a comprehensive UI overhaul and critical bug fixes for SpeakType. The primary focus is aligning the application’s visual language with the SpeedCursor reference design, introducing a unified ambient glow theme, refining the dashboard for improved data visualization, and fixing a critical history audio playback issue.


Key Changes

UI and Theming

Global Ambient Background

  • Implemented a reusable AmbientBackground component
  • Applied a unified red/blue gradient glow via MainView
  • Ensured the background persists across all screens

Transparent Views

  • Removed opaque backgrounds to allow the global ambient theme to show through:
    • DashboardView
    • HistoryView
    • TranscribeAudioView
    • SettingsView
    • Sidebar components

Dashboard Redesign

  • Stats Cards
    • Converted metric cards to a clean rectangular layout
    • Fixed height of 110pt with reduced padding (20pt)
  • Typography Improvements
    • Metric values set to 34pt
    • Icon size set to 32pt
    • Prevented truncation and improved readability
  • Tips and Tutorials Card
    • Dynamically matches the height of the metrics grid
  • Layout Alignment
    • Standardized global padding to 20pt
    • Aligned stats grid with the Recent Transcriptions section

Sidebar Refinement

  • Added the generic SpeedCursor logo header
  • Ensured full transparency to preserve the glassmorphism effect

Bug Fixes

History Audio Playback

  • Fixed an issue where recordings created from the Transcribe Audio tab did not persist the audio file URL
  • Resolved No audio recording available errors in History
  • Ensured all new recordings support playback

Settings Cleanup

  • Removed the redundant Microphone Input section from SettingsView
  • Consolidated microphone configuration into the dedicated Audio Input tab

AI Model Statistics

  • Updated ModelRow to display real-time speed and accuracy values from AIModel
  • Removed placeholder statistics

Files Modified

Views

  • speaktype/Views/MainView.swift

    • Applied global AmbientBackground
    • Removed solid background colors
  • speaktype/Views/Screens/Dashboard/DashboardView.swift

    • Layout overhaul (cards, grid, padding)
  • speaktype/Views/Screens/History/HistoryView.swift

    • UI polish and transparency updates
  • speaktype/Views/TranscribeAudioView.swift

    • Fixed audio file URL propagation to HistoryService
  • speaktype/Views/Screens/Settings/SettingsView.swift

    • Removed Microphone Input section
  • speaktype/Views/SidebarView.swift

    • Updated header branding and transparency
  • speaktype/Views/Components/ModelRow.swift

    • Implemented dynamic AI model stats UI
  • speaktype/Views/Components/AmbientBackground.swift

    • New reusable background component

Models and Services

  • speaktype/Models/AIModel.swift

    • Added speed and accuracy properties
  • speaktype/Services/HistoryService.swift

    • Verified audio persistence logic
  • speaktype/Constants/ColorSystem.swift

    • Centralized color definitions

Assets

  • speaktype/Assets.xcassets
    • Added AppLogo and background interactions
    • Removed unused textures

Visual Verification

  • Dashboard: Rectangular stat cards and consistent alignment verified
  • History: Audio playback controls appear for new recordings
  • Theme: Red/blue ambient glow visible across all screens

…ced model download UI

- Implemented comprehensive software update system with automatic 24-hour checking
- Added beautiful VoiceInk-style update dialog with release notes and action buttons
- Enhanced ModelRow UI with download progress bar, status text, and percentage display
- Added Software Update section in Settings with manual check and auto-update toggle
- Integrated update checking into app lifecycle (AppDelegate)
- Created AppVersion model with version comparison logic
- Created UpdateService for managing update checks and user preferences
- Shows blue download button and progress UI matching design reference
- Supports skip version, remind later, and install update actions
…modifier options

- Created HotkeyOption enum with 7 modifier key options (Fn, Right/Left Cmd, Ctrl, Option)
- Replaced simple Fn toggle with dropdown picker in Settings
- Implemented dynamic hotkey monitoring in AppDelegate
- Added automatic migration from old useFnKey setting
- Set Fn as default hotkey option
- Support for automatic hotkey switching without app restart
- All hotkeys display with proper symbols (⌘, ⌃, ⌥)
- Includes UserDefaults persistence and SwiftUI Binding support
…ection

Major Features:
- Enhanced history detail view with VoiceInk-style UI
- Audio playback with waveform visualization
- Real-time metrics display (duration, model, transcription time)
- Migrated audio storage from Documents to Application Support
- VoiceInk-style hotkey selection with multiple modifier options
- Automatic microphone detection with device selection UI

History Enhancements:
- Created AudioPlayerService for playback control
- Added WaveformView component with progress tracking
- Built HistoryDetailView with complete playback controls
- Updated HistoryItem model with audio URL, model, and timing
- Changed storage to in-memory Application Support directory

Hotkey System:
- Added HotkeyOption enum with 7 modifier keys (Fn, Cmd, Ctrl, Option)
- Replaced simple toggle with dropdown picker in Settings
- Implemented dynamic hotkey monitoring in AppDelegate
- Added automatic migration from old useFnKey setting

Microphone Features:
- Real-time device detection on plug/unplug
- Settings UI with dropdown to select input device
- Shows connected device count
- Automatic refresh when devices change
@karansinghgit
karansinghgit merged commit df4b0a9 into main Jan 18, 2026
aschwarzkopf added a commit to aschwarzkopf/speaktype that referenced this pull request Apr 24, 2026
Full code audit surfaced 15 bugs across 4 severity tiers; this commit
addresses 14 of them (karansinghgit#15 deferred — Polar.sh handles server-side). It
also introduces MiniRecorderViewModel, which fixes a subscription-timing
race that caused "box appears, disappears, no audio" when pressing the
hotkey.

All 58 unit tests pass. 2 pre-existing UI test failures are unrelated
(sidebar link lookups).

CRITICAL

karansinghgit#1 AudioRecordingService writer race — replaced `isStopping: Bool` with a
   RecordingStatus enum gated on audioQueue (RosyWriter pattern). All
   writer-state mutation now happens on audioQueue; concurrent/double
   stopRecording calls are safe.
karansinghgit#2 MiniRecorderView NSEvent monitor leak + duplicate Escape handling —
   deleted the global/local NSEvent monitors; introduced
   KeyableMiniRecorderPanel (canBecomeKey=true) so the existing
   KeyEventHandlerView becomes the sole Escape path.
karansinghgit#3 MiniRecorder state hygiene — fixed via the VM refactor below.

HIGH

karansinghgit#4 ModelDownloadService retry bounds — added `maxDownloadAttempts = 2`,
   `defer { activeTasks[variant] = nil }` for exactly-once handle cleanup.
karansinghgit#5 AIModel.recommendedModel force unwrap — replaced with precondition +
   guarded fallback to smallest model.
karansinghgit#6 TranscribeAudioView security-scoped resource — applied Apple's `defer`
   pattern, UUID-prefixed temp names, dropped unsound fallback to scoped
   URL after access was released.
karansinghgit#7 AudioPlayerService silent load failure — loadAudio now async throws;
   added @published var lastError for SwiftUI .alert(item:) observation;
   made the service @mainactor; updated 2 callers.
karansinghgit#8 LicenseManager race — added @published isValidatingLicense flag;
   network/transport failures no longer revoke cached license (only
   explicit server-confirmed invalid responses do), per RevenueCat /
   StoreKit 2 pattern.

MEDIUM

karansinghgit#9  WhisperService loadModel cancellation — pre-guard and post-guard
    Task.checkCancellation() per WWDC21 guidance; `defer` guarantees
    isLoading resets; late-cancelled pipe is discarded.
karansinghgit#10 ModelDownloadService deleteModel — dropped /tmp and ~/.cache paths;
    replaced substring `contains` match with exact last-path-component
    equality; extracted static `shouldDelete(fileName:patterns:)` for
    testability.
karansinghgit#11 UpdateService stale state — on network error, clear availableUpdate
    to avoid showing outdated update banner; added clearAvailableUpdate()
    helper.
karansinghgit#12 MiniRecorderView.barHeight clamp — defensive min/max on audioLevel
    before sqrt() to guard against upstream bugs producing NaN.

LOW

karansinghgit#13 HistoryService deleteItem — filter out-of-bounds offsets before
    `remove(atOffsets:)` to tolerate stale IndexSet during rapid deletes.
karansinghgit#14 MiniRecorderView debugLog — moved off world-readable /tmp to
    ~/Library/Application Support/SpeakType/Logs; gated behind #if DEBUG
    so release builds use print (unified logging) instead.

VM REFACTOR (Option D from research)

Fixes the "no audio on Fn press" bug introduced by karansinghgit#3's initial attempt
to use `.id(sessionID)` for SwiftUI @State reset. The .id() rebuild
forced SwiftUI to teardown/rebuild the view, but notifications posted
synchronously after the swap hit an empty subscriber list — recording
was never triggered.

- New MiniRecorderViewModel (@mainactor, ObservableObject) owns all
  session-lifecycle state: isListening, isProcessing, isWarmingUp,
  statusMessage, cancelCommit, sessionID, pendingAction
- Controller drives the VM directly via startSession/requestStop/
  requestCancel — no more NotificationCenter round-trip, no more .id()
  churn
- View observes via @ObservedObject; three .onReceive blocks collapsed
  into one .onChange(of: viewModel.pendingAction) draining consumeAction()
- SwiftUI guarantees @published subscribers are attached before any
  mutation is observed, eliminating the timing race

Test additions:
- 3 audio concurrency tests, 3 panel, 5 controller, 4 AIModel, 3 audio
  player, 2 license, 5 exact-match deletion + 1 retry bound, 1 Whisper
  cancellation, 2 update service, 2 history offset, 12 VM contract tests

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants