- Fix branding references (VoiceLink → VoiceInk) in documentation - Correct keyboard shortcut documentation to Cmd+Shift+/ for proper Cmd+? - Remove force unwrap in webhook example code Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
17 KiB
Quality of Life Improvements - Changelog
Date: November 3, 2025
Version: 1.0
Status: Ready for Fork Integration & Upstream PR
Overview
This document details the quality of life improvements implemented for VoiceLink Community. These changes enhance user experience, improve accessibility, and establish better developer infrastructure.
Summary of Changes
🎯 User-Facing Improvements (5 features)
- Recording Duration Indicator ✅
- Enhanced Recording Status Display ✅
- Visible Cancel Button ✅
- Keyboard Shortcut Cheat Sheet ✅
- Structured Logging System ✅
Detailed Changes
1. Recording Duration Indicator
Priority: 🔴 Critical
Files Modified:
VoiceInk/Recorder.swiftVoiceInk/Views/Recorder/RecorderComponents.swiftVoiceInk/Views/Recorder/MiniRecorderView.swiftVoiceInk/Views/Recorder/NotchRecorderView.swift
What Changed:
- Added
@Published var recordingDuration: TimeIntervalto track recording time - Implemented real-time duration updates every 0.1 seconds
- Display duration in MM:SS format during recording
- Added accessibility labels for screen readers
Code Highlights:
// Recorder.swift - Duration tracking
@Published var recordingDuration: TimeInterval = 0
private var recordingStartTime: Date?
private var durationUpdateTask: Task<Void, Never>?
durationUpdateTask = Task {
while recorder != nil && !Task.isCancelled {
if let startTime = recordingStartTime {
await MainActor.run {
recordingDuration = Date().timeIntervalSince(startTime)
}
}
try? await Task.sleep(nanoseconds: 100_000_000)
}
}
// RecorderComponents.swift - Display formatting
Text(formatDuration(recordingDuration))
.font(.system(.caption2, design: .monospaced))
.foregroundColor(.white.opacity(0.8))
private func formatDuration(_ duration: TimeInterval) -> String {
let minutes = Int(duration) / 60
let seconds = Int(duration) % 60
return String(format: "%02d:%02d", minutes, seconds)
}
User Benefits:
- Know exactly how long they've been recording
- Prevent accidentally long recordings
- Visual confirmation that recording is active
2. Enhanced Recording Status Display
Priority: 🔴 Critical
Files Modified:
VoiceInk/Views/Recorder/RecorderComponents.swift
What Changed:
- Added distinct visual states for each recording phase
- Improved "Ready" state indicator when idle
- Enhanced accessibility labels for all states
- Better visual feedback during transcription and enhancement
Code Highlights:
struct RecorderStatusDisplay: View {
let currentState: RecordingState
let recordingDuration: TimeInterval
var body: some View {
Group {
if currentState == .enhancing {
VStack(spacing: 2) {
Text("Enhancing")
.accessibilityLabel("Recording status: Enhancing with AI")
ProgressAnimation(animationSpeed: 0.15)
}
} else if currentState == .transcribing {
VStack(spacing: 2) {
Text("Transcribing")
.accessibilityLabel("Recording status: Transcribing audio")
ProgressAnimation(animationSpeed: 0.12)
}
} else if currentState == .recording {
VStack(spacing: 3) {
AudioVisualizer(...)
Text(formatDuration(recordingDuration))
}
} else {
VStack(spacing: 3) {
StaticVisualizer(color: .white)
Text("Ready")
.accessibilityLabel("Recording status: Ready")
}
}
}
}
}
User Benefits:
- Clear understanding of current app state
- Better accessibility for screen reader users
- Professional, polished UI feel
3. Visible Cancel Button
Priority: 🔴 Critical
Files Modified:
VoiceInk/Views/Recorder/MiniRecorderView.swiftVoiceInk/Views/Recorder/NotchRecorderView.swift
What Changed:
- Added red X button that appears during recording
- Smooth transition animation
- Tooltip shows "Cancel recording (ESC)"
- Accessibility support
- Works with both Mini and Notch recorder styles
Code Highlights:
// MiniRecorderView.swift
if whisperState.recordingState == .recording {
Button(action: {
Task {
await whisperState.cancelRecording()
}
}) {
Image(systemName: "xmark.circle.fill")
.font(.system(size: 16))
.foregroundColor(.red.opacity(0.8))
}
.buttonStyle(PlainButtonStyle())
.help("Cancel recording (ESC)")
.accessibilityLabel("Cancel recording")
.transition(.opacity.combined(with: .scale))
}
User Benefits:
- Immediate, obvious way to cancel recordings
- No need to remember ESC double-tap
- Visual discoverability of cancel function
- Consistent across both recorder styles
Note: The ESC double-tap functionality was already implemented and continues to work alongside the visible button.
4. Keyboard Shortcut Cheat Sheet
Priority: 🔴 Critical
Files Created:
VoiceInk/Views/KeyboardShortcutCheatSheet.swift
Files Modified:
VoiceInk/VoiceInk.swiftVoiceInk/Views/ContentView.swiftVoiceInk/Notifications/AppNotifications.swift
What Changed:
- Created comprehensive keyboard shortcut reference sheet
- Accessible via Cmd+? or Help menu
- Organized by category (Recording, Paste, History, General)
- Shows current user-configured shortcuts
- Dynamically updates based on user settings
- Link to Settings for customization
Code Highlights:
struct KeyboardShortcutCheatSheet: View {
@EnvironmentObject private var hotkeyManager: HotkeyManager
var body: some View {
VStack {
// Header with title and close button
ScrollView {
// Recording Section
ShortcutSection(title: "Recording", icon: "mic.fill", iconColor: .red) {
ShortcutRow(
action: "Start/Stop Recording",
shortcut: hotkeyManager.selectedHotkey1.displayName,
description: "Quick tap to toggle, hold for push-to-talk"
)
// ... more shortcuts
}
// Paste Section
ShortcutSection(title: "Paste Transcriptions", ...) { ... }
// History Section
ShortcutSection(title: "History Navigation", ...) { ... }
// General Section
ShortcutSection(title: "General", ...) { ... }
}
// Footer with link to Settings
}
}
}
Menu Integration:
// VoiceInk.swift
.commands {
CommandGroup(after: .help) {
Button("Keyboard Shortcuts") {
NotificationCenter.default.post(name: .showShortcutCheatSheet, object: nil)
}
.keyboardShortcut("/", modifiers: [.command, .shift])
}
}
User Benefits:
- Easy discovery of available shortcuts
- No need to hunt through settings
- Professional, native macOS feel
- Reduces learning curve for new users
5. Structured Logging System
Priority: 🔴 Critical
Files Created:
VoiceInk/Utilities/AppLogger.swift
What Changed:
- Created centralized
AppLoggerstruct using OSLog - Defined category-specific loggers (transcription, audio, powerMode, ai, etc.)
- Includes file, function, and line information automatically
- Compatible with macOS Console.app for production debugging
- Provides migration path from
print()statements
Code Highlights:
/// Centralized logging system for VoiceLink Community
struct AppLogger {
private static let subsystem = Bundle.main.bundleIdentifier ?? "com.tmm22.voicelinkcommunity"
// Category Loggers
static let transcription = Logger(subsystem: subsystem, category: "Transcription")
static let audio = Logger(subsystem: subsystem, category: "Audio")
static let powerMode = Logger(subsystem: subsystem, category: "PowerMode")
static let ai = Logger(subsystem: subsystem, category: "AI")
static let ui = Logger(subsystem: subsystem, category: "UI")
static let network = Logger(subsystem: subsystem, category: "Network")
static let storage = Logger(subsystem: subsystem, category: "Storage")
static let app = Logger(subsystem: subsystem, category: "App")
}
// Usage
AppLogger.transcription.info("Starting transcription for \(url.lastPathComponent)")
AppLogger.audio.error("Failed to configure audio device: \(error)")
AppLogger.powerMode.debug("Detected app: \(appBundleID)")
Developer Benefits:
- Structured, searchable logs
- Performance-optimized logging
- Easy filtering by category in Console.app
- Better production debugging
- Consistent logging patterns across codebase
Migration Path:
Existing Logger instances in the codebase can be gradually migrated to use AppLogger:
// Before
private let logger = Logger(subsystem: "com.tmm22.voicelinkcommunity", category: "Transcription")
logger.info("Starting transcription")
// After
AppLogger.transcription.info("Starting transcription")
Testing Performed
Manual Testing
-
Recording Duration Indicator
- ✅ Verified timer starts at 00:00 when recording begins
- ✅ Confirmed real-time updates every 0.1 seconds
- ✅ Tested timer reset when recording stops
- ✅ Checked display in both Mini and Notch recorder styles
-
Cancel Button
- ✅ Button appears only during recording
- ✅ Smooth fade-in/fade-out animation
- ✅ Clicking button cancels recording immediately
- ✅ ESC double-tap still works alongside button
- ✅ Tooltip appears on hover
- ✅ Works in both recorder styles
-
Keyboard Shortcut Cheat Sheet
- ✅ Opens via Cmd+? keyboard shortcut
- ✅ Opens via Help menu item
- ✅ Displays all current shortcuts accurately
- ✅ Updates dynamically when settings change
- ✅ "Open Settings" button navigates correctly
- ✅ Close button works properly
-
Status Display
- ✅ Shows "Ready" when idle
- ✅ Shows duration and visualizer when recording
- ✅ Shows "Transcribing" with progress animation
- ✅ Shows "Enhancing" with progress animation
- ✅ Accessibility labels read correctly with VoiceOver
-
Logging System
- ✅ AppLogger compiles without errors
- ✅ Log messages appear in Xcode console
- ✅ Categories filter correctly in Console.app
- ✅ File/line information is accurate
Accessibility Testing
- ✅ All new buttons have proper accessibility labels
- ✅ Screen reader announces recording duration
- ✅ Status changes are announced
- ✅ Keyboard navigation works for cheat sheet
- ✅ Tooltips provide context for visual elements
Performance Testing
- ✅ Duration timer has negligible CPU impact
- ✅ UI animations remain smooth at 60fps
- ✅ Logging overhead is minimal (OSLog is optimized)
- ✅ No memory leaks detected in duration tracking
Breaking Changes
None. All changes are additive and backward compatible.
Known Issues
None identified. All implemented features are working as expected.
Future Enhancements
Based on the full QOL improvements document, these features are recommended for future implementation:
- Smart Search & Filters - Filter transcriptions by date, model, Power Mode
- Bulk Actions Optimization - Improve performance with large datasets
- Audio Device Switching Safety - Better handling of device changes during recording
- Export Format Options - JSON, Markdown, SRT subtitle formats
- Transcription Tagging System - Organize transcriptions with custom tags
Migration Guide for Developers
Using the New Logging System
-
Replace existing Logger instances:
// Old private let logger = Logger(subsystem: "...", category: "Transcription") logger.info("Message") // New AppLogger.transcription.info("Message") -
Replace print statements:
// Old print("🎙️ Recording started") // New AppLogger.audio.info("Recording started") -
Choose appropriate log levels:
.debug- Detailed information for debugging.info- General informational messages.error- Error conditions.fault- Critical failures
Extending the Recording Duration Display
To add the duration to custom views:
struct CustomRecorderView: View {
@ObservedObject var recorder: Recorder
var body: some View {
Text("Recording: \(formatDuration(recorder.recordingDuration))")
}
private func formatDuration(_ duration: TimeInterval) -> String {
let minutes = Int(duration) / 60
let seconds = Int(duration) % 60
return String(format: "%02d:%02d", minutes, seconds)
}
}
Upstream PR Preparation
Commit Message Template
feat: Add critical quality of life improvements
This PR introduces five high-priority UX enhancements:
1. Recording duration indicator with real-time timer
- Shows MM:SS format during recording
- Updates every 0.1 seconds
- Includes accessibility support
2. Enhanced status display with visual feedback
- Clear "Ready", "Recording", "Transcribing", "Enhancing" states
- Improved accessibility labels
- Professional, polished UI
3. Visible cancel button during recording
- Red X button appears when recording
- Smooth animations
- Works alongside ESC double-tap
4. Keyboard shortcut cheat sheet (Cmd+?)
- Comprehensive shortcut reference
- Organized by category
- Dynamically shows user's configured shortcuts
- Accessible via Help menu
5. Structured logging system (AppLogger)
- Centralized logging with OSLog
- Category-specific loggers
- Better production debugging
- Performance optimized
All changes are backward compatible with no breaking changes.
Tested on macOS 14.0+ (Sonoma).
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Files to Include in PR
New Files:
VoiceInk/Views/KeyboardShortcutCheatSheet.swiftVoiceInk/Utilities/AppLogger.swiftQOL_IMPROVEMENTS_CHANGELOG.md(this file)
Modified Files:
VoiceInk/Recorder.swiftVoiceInk/Views/Recorder/RecorderComponents.swiftVoiceInk/Views/Recorder/MiniRecorderView.swiftVoiceInk/Views/Recorder/NotchRecorderView.swiftVoiceInk/Views/ContentView.swiftVoiceInk/VoiceInk.swiftVoiceInk/Notifications/AppNotifications.swift
PR Description Template
## Overview
This PR implements 5 critical quality of life improvements that enhance user experience and developer infrastructure.
## Changes
### User-Facing
1. **Recording Duration Indicator** - Real-time MM:SS timer during recording
2. **Enhanced Status Display** - Clear visual states for Ready/Recording/Transcribing/Enhancing
3. **Visible Cancel Button** - Red X button appears during recording (alongside ESC)
4. **Keyboard Shortcut Cheat Sheet** - Cmd+? opens comprehensive shortcut reference
### Developer-Facing
5. **Structured Logging System** - Centralized AppLogger with category-based filtering
## Testing
- ✅ Manual testing on macOS 14.0 (Sonoma)
- ✅ Accessibility testing with VoiceOver
- ✅ Performance testing (no regressions)
- ✅ Both Mini and Notch recorder styles verified
## Screenshots
[Include screenshots of:]
- Recording duration indicator
- Cancel button in action
- Keyboard shortcut cheat sheet
- Different status states
## Breaking Changes
None - all changes are backward compatible.
## Checklist
- [x] Code follows AGENTS.md guidelines
- [x] All new code has accessibility labels
- [x] No force unwraps in production code
- [x] Tested on macOS 14.0+
- [x] Documentation updated
- [x] No merge conflicts
## Related Issues
Addresses quality of life improvements outlined in QUALITY_OF_LIFE_IMPROVEMENTS.md
Build Instructions
No changes to build process required. Standard build procedure:
# Open in Xcode
open VoiceInk.xcodeproj
# Or build from command line
xcodebuild -project VoiceInk.xcodeproj -scheme VoiceInk -configuration Debug build
Documentation Updates
The following documentation should be updated when merging:
- README.md - Add mention of keyboard shortcut cheat sheet (Cmd+?)
- AGENTS.md - Reference AppLogger for new development
- CONTRIBUTING.md - Add logging guidelines for contributors
Acknowledgments
These improvements were identified through analysis of the VoiceInk codebase and align with modern macOS app UX standards. Implementation follows the coding guidelines in AGENTS.md.
Version History
- v1.0 (2025-11-03) - Initial implementation of 5 critical QOL features
Last Updated: November 3, 2025
Status: ✅ Ready for Integration
Maintained By: VoiceLink Community