vOOice/QOL_IMPROVEMENTS_CHANGELOG.md
Deborah Mangan 93a790833e fix: Address AI code reviewer feedback
- 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>
2025-11-03 11:55:59 +10:00

587 lines
17 KiB
Markdown

# 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)
1. **Recording Duration Indicator**
2. **Enhanced Recording Status Display**
3. **Visible Cancel Button**
4. **Keyboard Shortcut Cheat Sheet**
5. **Structured Logging System**
---
## Detailed Changes
### 1. Recording Duration Indicator
**Priority:** 🔴 Critical
**Files Modified:**
- `VoiceInk/Recorder.swift`
- `VoiceInk/Views/Recorder/RecorderComponents.swift`
- `VoiceInk/Views/Recorder/MiniRecorderView.swift`
- `VoiceInk/Views/Recorder/NotchRecorderView.swift`
**What Changed:**
- Added `@Published var recordingDuration: TimeInterval` to 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:**
```swift
// 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:**
```swift
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.swift`
- `VoiceInk/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:**
```swift
// 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.swift`
- `VoiceInk/Views/ContentView.swift`
- `VoiceInk/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:**
```swift
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:**
```swift
// 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 `AppLogger` struct 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:**
```swift
/// 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`:
```swift
// 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
1. **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
2. **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
3. **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
4. **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
5. **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:
1. **Smart Search & Filters** - Filter transcriptions by date, model, Power Mode
2. **Bulk Actions Optimization** - Improve performance with large datasets
3. **Audio Device Switching Safety** - Better handling of device changes during recording
4. **Export Format Options** - JSON, Markdown, SRT subtitle formats
5. **Transcription Tagging System** - Organize transcriptions with custom tags
---
## Migration Guide for Developers
### Using the New Logging System
1. **Replace existing Logger instances:**
```swift
// Old
private let logger = Logger(subsystem: "...", category: "Transcription")
logger.info("Message")
// New
AppLogger.transcription.info("Message")
```
2. **Replace print statements:**
```swift
// Old
print("🎙️ Recording started")
// New
AppLogger.audio.info("Recording started")
```
3. **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:
```swift
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.swift`
- `VoiceInk/Utilities/AppLogger.swift`
- `QOL_IMPROVEMENTS_CHANGELOG.md` (this file)
**Modified Files:**
- `VoiceInk/Recorder.swift`
- `VoiceInk/Views/Recorder/RecorderComponents.swift`
- `VoiceInk/Views/Recorder/MiniRecorderView.swift`
- `VoiceInk/Views/Recorder/NotchRecorderView.swift`
- `VoiceInk/Views/ContentView.swift`
- `VoiceInk/VoiceInk.swift`
- `VoiceInk/Notifications/AppNotifications.swift`
### PR Description Template
```markdown
## 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:
```bash
# 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:
1. **README.md** - Add mention of keyboard shortcut cheat sheet (Cmd+?)
2. **AGENTS.md** - Reference AppLogger for new development
3. **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