feat: implement Dynamic Type with Apple text styles

Replace all custom Theme.FontSize values and hardcoded font sizes with
Apple's built-in text styles (.largeTitle, .title2, .headline, .body,
.subheadline, .caption, .caption2) to support accessibility scaling.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-01-11 10:23:16 -06:00
parent 8affa3ce0d
commit 2d48f1411a
16 changed files with 273 additions and 284 deletions

View File

@@ -96,11 +96,11 @@ struct PhotoImportView: View {
VStack(spacing: Theme.Spacing.sm) {
Text("Import from Photos")
.font(.system(size: Theme.FontSize.sectionTitle, weight: .bold, design: .rounded))
.font(.title2)
.foregroundStyle(Theme.textPrimary(colorScheme))
Text("Select photos taken at stadiums to automatically log your visits. We'll use GPS and date data to match them to games.")
.font(.system(size: Theme.FontSize.body))
.font(.body)
.foregroundStyle(Theme.textSecondary(colorScheme))
.multilineTextAlignment(.center)
.padding(.horizontal, Theme.Spacing.xl)
@@ -114,7 +114,7 @@ struct PhotoImportView: View {
Image(systemName: "photo.stack")
Text("Select Photos")
}
.font(.system(size: Theme.FontSize.body, weight: .semibold))
.font(.body)
.foregroundStyle(.white)
.frame(maxWidth: .infinity)
.padding(Theme.Spacing.md)
@@ -137,7 +137,7 @@ struct PhotoImportView: View {
Image(systemName: "info.circle.fill")
.foregroundStyle(Theme.warmOrange)
Text("How it works")
.font(.system(size: Theme.FontSize.body, weight: .semibold))
.font(.body)
}
VStack(alignment: .leading, spacing: Theme.Spacing.xs) {
@@ -147,7 +147,7 @@ struct PhotoImportView: View {
InfoRow(icon: "hand.tap", text: "You confirm or edit the rest")
}
}
.font(.system(size: Theme.FontSize.caption))
.font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme))
.padding(Theme.Spacing.md)
.background(Theme.cardBackground(colorScheme))
@@ -164,11 +164,11 @@ struct PhotoImportView: View {
ThemedSpinner(size: 50, lineWidth: 4)
Text("Processing photos...")
.font(.system(size: Theme.FontSize.body, weight: .medium))
.font(.body)
.foregroundStyle(Theme.textSecondary(colorScheme))
Text("\(viewModel.processedCount) of \(viewModel.totalCount) photos")
.font(.system(size: Theme.FontSize.caption))
.font(.subheadline)
.foregroundStyle(Theme.textMuted(colorScheme))
Spacer()
@@ -222,7 +222,7 @@ struct PhotoImportView: View {
Image(systemName: "plus.circle")
Text("Add More Photos")
}
.font(.system(size: Theme.FontSize.body))
.font(.body)
.foregroundStyle(Theme.warmOrange)
}
.padding(.top, Theme.Spacing.md)
@@ -259,11 +259,11 @@ struct PhotoImportView: View {
private func summaryBadge(count: Int, label: String, color: Color) -> some View {
VStack(spacing: 4) {
Text("\(count)")
.font(.system(size: Theme.FontSize.sectionTitle, weight: .bold, design: .rounded))
.font(.title2)
.foregroundStyle(color)
Text(label)
.font(.system(size: Theme.FontSize.caption))
.font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme))
}
.frame(maxWidth: .infinity)
@@ -283,10 +283,10 @@ struct PhotoImportView: View {
.foregroundStyle(color)
VStack(alignment: .leading, spacing: 2) {
Text(title)
.font(.system(size: Theme.FontSize.body, weight: .semibold))
.font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme))
Text(subtitle)
.font(.system(size: Theme.FontSize.caption))
.font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme))
}
Spacer()
@@ -372,7 +372,7 @@ struct PhotoImportCandidateCard: View {
.foregroundStyle(isConfirmed ? .green : Theme.textMuted(colorScheme))
}
}
.font(.system(size: Theme.FontSize.caption))
.font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme))
// Match result
@@ -407,10 +407,10 @@ struct PhotoImportCandidateCard: View {
HStack {
VStack(alignment: .leading, spacing: 2) {
Text("\(matches.count) possible games")
.font(.system(size: Theme.FontSize.body, weight: .medium))
.font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme))
Text("Tap to select the correct game")
.font(.system(size: Theme.FontSize.caption))
.font(.subheadline)
.foregroundStyle(Theme.warmOrange)
}
Spacer()
@@ -424,7 +424,7 @@ struct PhotoImportCandidateCard: View {
Image(systemName: "exclamationmark.triangle")
.foregroundStyle(.red)
Text(reason.description)
.font(.system(size: Theme.FontSize.caption))
.font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme))
}
}
@@ -434,7 +434,7 @@ struct PhotoImportCandidateCard: View {
VStack(alignment: .leading, spacing: 4) {
HStack {
Text(match.matchupDescription)
.font(.system(size: Theme.FontSize.body, weight: .semibold))
.font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme))
Image(systemName: match.game.sport.iconName)
@@ -442,7 +442,7 @@ struct PhotoImportCandidateCard: View {
}
Text("\(match.stadium.name)\(match.gameDateTime)")
.font(.system(size: Theme.FontSize.caption))
.font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme))
// Confidence badge
@@ -463,7 +463,7 @@ struct PhotoImportCandidateCard: View {
}()
return Text(text)
.font(.system(size: 10, weight: .medium))
.font(.caption2)
.foregroundStyle(color)
.padding(.horizontal, 6)
.padding(.vertical, 2)
@@ -496,7 +496,7 @@ struct GameMatchPickerSheet: View {
VStack(alignment: .leading, spacing: 4) {
HStack {
Text(match.fullMatchupDescription)
.font(.system(size: Theme.FontSize.body, weight: .medium))
.font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme))
Spacer()
@@ -506,7 +506,7 @@ struct GameMatchPickerSheet: View {
}
Text("\(match.stadium.name)\(match.gameDateTime)")
.font(.system(size: Theme.FontSize.caption))
.font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme))
}
.padding(.vertical, 4)