v1.1 polish: accessibility, error logging, localization, and code quality sweep

- Wrap 30+ production print() statements in #if DEBUG guards across 18 files
- Add VoiceOver labels, hints, and traits to Watch app, Live Activities, widgets
- Add .accessibilityAddTraits(.isButton) to 15+ onTapGesture views
- Add text alternatives for color-only indicators (progress dots, mood circles)
- Localize raw string literals in NoteEditorView, EntryDetailView, widgets
- Replace 25+ silent try? with do/catch + AppLogger error logging
- Replace hardcoded font sizes with semantic Dynamic Type fonts
- Fix FIXME in IconPickerView (log icon change errors)
- Extract magic animation delays to named constants across 8 files
- Add widget empty state "Log your first mood!" messaging
- Hide decorative images from VoiceOver, add labels to ColorPickers
- Remove stale TODO in Color+Codable (alpha change deferred for migration)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Trey T
2026-03-26 20:09:14 -05:00
parent 4d9e906c4d
commit 1f040ab676
41 changed files with 427 additions and 107 deletions

View File

@@ -9,6 +9,7 @@
#if DEBUG
import SwiftUI
import UIKit
import os.log
/// Exports widget previews to PNG files for App Store screenshots
@MainActor
@@ -76,7 +77,12 @@ class WidgetExporter {
// Clean and create export directory
try? FileManager.default.removeItem(at: exportPath)
try? FileManager.default.createDirectory(at: exportPath, withIntermediateDirectories: true)
do {
try FileManager.default.createDirectory(at: exportPath, withIntermediateDirectories: true)
} catch {
AppLogger.export.error("Failed to create widget export directory: \(error)")
return nil
}
var totalExported = 0
@@ -85,7 +91,12 @@ class WidgetExporter {
for iconOption in allIcons {
let folderName = "\(tintOption.name)_\(iconOption.name)"
let variantPath = exportPath.appendingPathComponent(folderName, isDirectory: true)
try? FileManager.default.createDirectory(at: variantPath, withIntermediateDirectories: true)
do {
try FileManager.default.createDirectory(at: variantPath, withIntermediateDirectories: true)
} catch {
AppLogger.export.error("Failed to create variant directory '\(folderName)': \(error)")
continue
}
let config = WidgetExportConfig(
moodTint: tintOption.tint,
@@ -155,7 +166,12 @@ class WidgetExporter {
let exportPath = documentsPath.appendingPathComponent("WidgetExports_Current", isDirectory: true)
try? FileManager.default.removeItem(at: exportPath)
try? FileManager.default.createDirectory(at: exportPath, withIntermediateDirectories: true)
do {
try FileManager.default.createDirectory(at: exportPath, withIntermediateDirectories: true)
} catch {
AppLogger.export.error("Failed to create current config export directory: \(error)")
return nil
}
let config = WidgetExportConfig(
moodTint: UserDefaultsStore.moodTintable(),
@@ -177,7 +193,12 @@ class WidgetExporter {
// Clean and create export directory
try? FileManager.default.removeItem(at: exportPath)
try? FileManager.default.createDirectory(at: exportPath, withIntermediateDirectories: true)
do {
try FileManager.default.createDirectory(at: exportPath, withIntermediateDirectories: true)
} catch {
AppLogger.export.error("Failed to create voting layout export directory: \(error)")
return nil
}
var totalExported = 0
@@ -186,7 +207,12 @@ class WidgetExporter {
for iconOption in allIcons {
let folderName = "\(tintOption.name)_\(iconOption.name)"
let variantPath = exportPath.appendingPathComponent(folderName, isDirectory: true)
try? FileManager.default.createDirectory(at: variantPath, withIntermediateDirectories: true)
do {
try FileManager.default.createDirectory(at: variantPath, withIntermediateDirectories: true)
} catch {
AppLogger.export.error("Failed to create voting variant directory '\(folderName)': \(error)")
continue
}
let config = WidgetExportConfig(
moodTint: tintOption.tint,
@@ -372,7 +398,11 @@ class WidgetExporter {
if let image = renderer.uiImage {
let url = folder.appendingPathComponent("\(name).png")
if let data = image.pngData() {
try? data.write(to: url)
do {
try data.write(to: url)
} catch {
AppLogger.export.error("Failed to write widget image '\(name)': \(error)")
}
}
}
}
@@ -384,7 +414,11 @@ class WidgetExporter {
if let image = renderer.uiImage {
let url = folder.appendingPathComponent("\(name).png")
if let data = image.pngData() {
try? data.write(to: url)
do {
try data.write(to: url)
} catch {
AppLogger.export.error("Failed to write live activity image '\(name)': \(error)")
}
}
}
}