This commit provides comprehensive documentation and source files for 5 critical quality of life improvements: 1. Recording duration indicator with real-time timer 2. Enhanced status display with visual feedback 3. Visible cancel button during recording 4. Keyboard shortcut cheat sheet (Cmd+?) 5. Structured logging system (AppLogger) Included Files: - Complete source files for new features - Step-by-step application guide - Detailed technical documentation - Full analysis with 40+ improvement ideas See APPLYING_QOL_IMPROVEMENTS.md for instructions on how to apply these improvements to the codebase. All changes are backward compatible with no breaking changes. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
171 lines
5.4 KiB
Swift
171 lines
5.4 KiB
Swift
import Foundation
|
||
import OSLog
|
||
|
||
/// Centralized logging system for VoiceLink Community
|
||
///
|
||
/// Provides structured, categorized logging with consistent formatting across the application.
|
||
/// Uses OSLog for performance and integration with macOS Console.app.
|
||
///
|
||
/// ## Usage
|
||
/// ```swift
|
||
/// AppLogger.transcription.info("Starting transcription for \(audioURL.lastPathComponent)")
|
||
/// AppLogger.audio.error("Failed to configure audio device: \(error)")
|
||
/// ```
|
||
struct AppLogger {
|
||
private init() {}
|
||
|
||
// MARK: - Subsystem
|
||
|
||
private static let subsystem = Bundle.main.bundleIdentifier ?? "com.tmm22.voicelinkcommunity"
|
||
|
||
// MARK: - Category Loggers
|
||
|
||
/// Logger for transcription operations
|
||
///
|
||
/// Use for:
|
||
/// - Starting/stopping transcription
|
||
/// - Model loading/unloading
|
||
/// - Transcription results
|
||
/// - Transcription errors
|
||
static let transcription = Logger(subsystem: subsystem, category: "Transcription")
|
||
|
||
/// Logger for audio operations
|
||
///
|
||
/// Use for:
|
||
/// - Audio device configuration
|
||
/// - Recording start/stop
|
||
/// - Audio level monitoring
|
||
/// - Audio file operations
|
||
static let audio = Logger(subsystem: subsystem, category: "Audio")
|
||
|
||
/// Logger for Power Mode operations
|
||
///
|
||
/// Use for:
|
||
/// - Power Mode activation/deactivation
|
||
/// - Configuration application
|
||
/// - App/URL detection
|
||
/// - Session management
|
||
static let powerMode = Logger(subsystem: subsystem, category: "PowerMode")
|
||
|
||
/// Logger for AI enhancement operations
|
||
///
|
||
/// Use for:
|
||
/// - AI provider communication
|
||
/// - Enhancement requests/responses
|
||
/// - Prompt processing
|
||
/// - Context capture
|
||
static let ai = Logger(subsystem: subsystem, category: "AI")
|
||
|
||
/// Logger for UI operations
|
||
///
|
||
/// Use for:
|
||
/// - Window management
|
||
/// - View lifecycle
|
||
/// - User interactions
|
||
/// - UI state changes
|
||
static let ui = Logger(subsystem: subsystem, category: "UI")
|
||
|
||
/// Logger for network operations
|
||
///
|
||
/// Use for:
|
||
/// - API requests/responses
|
||
/// - Network errors
|
||
/// - TTS provider calls
|
||
/// - Cloud transcription
|
||
static let network = Logger(subsystem: subsystem, category: "Network")
|
||
|
||
/// Logger for storage operations
|
||
///
|
||
/// Use for:
|
||
/// - SwiftData operations
|
||
/// - File I/O
|
||
/// - Keychain access
|
||
/// - UserDefaults
|
||
static let storage = Logger(subsystem: subsystem, category: "Storage")
|
||
|
||
/// Logger for general application lifecycle
|
||
///
|
||
/// Use for:
|
||
/// - App launch/termination
|
||
/// - Initialization
|
||
/// - Configuration
|
||
/// - Critical errors
|
||
static let app = Logger(subsystem: subsystem, category: "App")
|
||
|
||
// MARK: - Convenience Methods
|
||
|
||
/// Log a transcription event
|
||
static func logTranscription(_ message: String, level: OSLogType = .info, file: String = #file, function: String = #function, line: Int = #line) {
|
||
log(message, logger: transcription, level: level, file: file, function: function, line: line)
|
||
}
|
||
|
||
/// Log an audio event
|
||
static func logAudio(_ message: String, level: OSLogType = .info, file: String = #file, function: String = #function, line: Int = #line) {
|
||
log(message, logger: audio, level: level, file: file, function: function, line: line)
|
||
}
|
||
|
||
/// Log a Power Mode event
|
||
static func logPowerMode(_ message: String, level: OSLogType = .info, file: String = #file, function: String = #function, line: Int = #line) {
|
||
log(message, logger: powerMode, level: level, file: file, function: function, line: line)
|
||
}
|
||
|
||
/// Log an AI enhancement event
|
||
static func logAI(_ message: String, level: OSLogType = .info, file: String = #file, function: String = #function, line: Int = #line) {
|
||
log(message, logger: ai, level: level, file: file, function: function, line: line)
|
||
}
|
||
|
||
// MARK: - Private Helpers
|
||
|
||
private static func log(_ message: String, logger: Logger, level: OSLogType, file: String, function: String, line: Int) {
|
||
let fileName = URL(fileURLWithPath: file).lastPathComponent
|
||
let context = "[\(fileName):\(line) \(function)]"
|
||
|
||
switch level {
|
||
case .debug:
|
||
logger.debug("\(context) \(message)")
|
||
case .info:
|
||
logger.info("\(context) \(message)")
|
||
case .error:
|
||
logger.error("\(context) \(message)")
|
||
case .fault:
|
||
logger.fault("\(context) \(message)")
|
||
default:
|
||
logger.log("\(context) \(message)")
|
||
}
|
||
}
|
||
}
|
||
|
||
// MARK: - OSLogType Extension
|
||
|
||
extension OSLogType {
|
||
/// Human-readable description of log level
|
||
var description: String {
|
||
switch self {
|
||
case .debug: return "DEBUG"
|
||
case .info: return "INFO"
|
||
case .error: return "ERROR"
|
||
case .fault: return "FAULT"
|
||
default: return "LOG"
|
||
}
|
||
}
|
||
}
|
||
|
||
// MARK: - Migration Helpers
|
||
|
||
#if DEBUG
|
||
/// Helper to identify print statements that should be migrated to AppLogger
|
||
///
|
||
/// Usage in development:
|
||
/// ```swift
|
||
/// // Instead of:
|
||
/// print("🎙️ Recording started")
|
||
///
|
||
/// // Use:
|
||
/// AppLogger.audio.info("Recording started")
|
||
/// ```
|
||
@available(*, deprecated, message: "Use AppLogger instead")
|
||
func debugPrint(_ items: Any..., separator: String = " ", terminator: String = "\n") {
|
||
Swift.print("⚠️ [DEPRECATED] Use AppLogger:", items, separator: separator, terminator: terminator)
|
||
}
|
||
#endif
|