feat(ui): add app-wide text size / UI scale option - #406
Open
xejarque wants to merge 1 commit into
Open
Conversation
Adds a "Text Size" picker under Settings → Appearance with four presets (Default, Large, Extra Large, Extra Extra Large) that scales the whole app UI proportionally. - iOS: scales via the SwiftUI `.dynamicTypeSize` environment override, which propagates to semantic fonts, SF Symbols and `@ScaledMetric`. - Mac "Designed for iPad": Dynamic Type is disabled by the platform, so a render-time zoom (`UIScaleContainer`) scales the entire window using the compensating-frame trick to keep scroll metrics and hit targets consistent. No-op on iOS. - Converts key layout metrics (chat input, theme cards, onboarding, path editing) to `@ScaledMetric(relativeTo: .body)` so icons and spacing grow at the same rate as text; safe by construction at the default preset (1.0x). - Persists via `PersistenceKeys` + `BackupUserDefaults` (backup/restore included), following the existing `colorSchemePreference` pattern. - Localized in all 10 languages; regenerated L10n via SwiftGen. - Adds ThemeService tests for default/unknown/refresh/restore paths and the dynamicTypeSize/uiScale mappings. Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
xejarque
force-pushed
the
feat/ui-scale
branch
from
August 20, 2026 10:09
65d5e3b to
15f4529
Compare
There was a problem hiding this comment.
Pull request overview
Adds an app-wide UI text size / scale preference and wires it through persistence, backup/restore, settings UI, and a set of layout metrics so the interface scales proportionally across the app (with a special render-scale path for “Designed for iPad” on macOS where Dynamic Type is disabled).
Changes:
- Introduces
AppUITextSizePreferencewith Dynamic Type + Mac UI scale mappings, persisted viaThemeServiceandPersistenceKeys, and included inBackupUserDefaults. - Adds a “Text Size” picker under Settings → Appearance and applies the chosen preference at the app root.
- Updates multiple views’ layout constants to
@ScaledMetric(relativeTo: .body)so spacing/controls scale with the preference, and adds test coverage for preference persistence/refresh/restore behavior.
Reviewed changes
Copilot reviewed 35 out of 36 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| MC1Tests/ThemeServiceTests.swift | Adds tests covering text-size preference persistence, refresh, and backup/restore downgrade behavior. |
| MC1Services/Sources/MC1Services/Utilities/PersistenceKeys.swift | Adds a new UserDefaults key for the text-size preference raw value. |
| MC1Services/Sources/MC1Services/Services/BackupUserDefaults.swift | Adds backup/restore mapping for the text-size preference. |
| MC1/Views/Support/Sections/ThemesPurchaseSection.swift | Converts theme grid/card metrics to @ScaledMetric for proportional scaling. |
| MC1/Views/Support/Components/ThemePreviewCard.swift | Scales badge spacing/padding with @ScaledMetric. |
| MC1/Views/Support/Components/ThemeBundleCard.swift | Scales card corner radius with @ScaledMetric. |
| MC1/Views/PathEditing/PathEditingSheet.swift | Scales row tap target min height with @ScaledMetric. |
| MC1/Views/PathEditing/PathEditCTALabel.swift | Scales CTA icon spacing/size with @ScaledMetric. |
| MC1/Views/PathEditing/AddHopPickerView.swift | Scales picker row spacing/badges/tap targets with @ScaledMetric. |
| MC1/Views/Onboarding/WelcomeView.swift | Scales onboarding hero size and spacing with @ScaledMetric. |
| MC1/Views/Onboarding/TroubleshootingSheet.swift | Scales title stack spacing with @ScaledMetric. |
| MC1/Views/Onboarding/RegionStepView.swift | Scales onboarding layout metrics (spacing/padding/corner radius/hit targets) with @ScaledMetric. |
| MC1/Views/Onboarding/PulsingAntenna.swift | Scales icon and hero frame size with @ScaledMetric. |
| MC1/Views/Onboarding/PresetStepView.swift | Scales preset onboarding layout metrics with @ScaledMetric. |
| MC1/Views/Onboarding/PermissionsView.swift | Scales permissions onboarding layout metrics with @ScaledMetric. |
| MC1/Views/Onboarding/NoDeviceSheet.swift | Scales sheet spacing/padding/hit targets with @ScaledMetric. |
| MC1/Views/Onboarding/DeviceScanView.swift | Scales device scan layout metrics with @ScaledMetric. |
| MC1/Views/Components/UIScaleContainer.swift | Adds render-time zoom container for “Designed for iPad” on macOS. |
| MC1/Views/Chats/Components/ChatShareMenu.swift | Scales chat share control sizing and uses semantic font weight. |
| MC1/Views/Chats/Components/ChatInputBar.swift | Scales input control height/corner radius/border width and updates background helper signature accordingly. |
| MC1/Views/Appearance/Components/ThemeSelectionCard.swift | Scales theme selection card metrics with @ScaledMetric. |
| MC1/Views/Appearance/AppearanceView.swift | Adds “Text Size” section/picker and scales theme grid layout metrics. |
| MC1/Theme/ThemeService.swift | Adds state + persistence + refresh logic for the text-size preference. |
| MC1/Theme/AppUITextSizePreference.swift | Introduces the preference enum and its Dynamic Type / UI scale mappings. |
| MC1/Resources/Localization/zh-Hans.lproj/Settings.strings | Adds localized “Text Size” strings (Simplified Chinese). |
| MC1/Resources/Localization/uk.lproj/Settings.strings | Adds localized “Text Size” strings (Ukrainian). |
| MC1/Resources/Localization/ru.lproj/Settings.strings | Adds localized “Text Size” strings (Russian). |
| MC1/Resources/Localization/pl.lproj/Settings.strings | Adds localized “Text Size” strings (Polish). |
| MC1/Resources/Localization/nl.lproj/Settings.strings | Adds localized “Text Size” strings (Dutch). |
| MC1/Resources/Localization/it.lproj/Settings.strings | Adds localized “Text Size” strings (Italian). |
| MC1/Resources/Localization/fr.lproj/Settings.strings | Adds localized “Text Size” strings (French). |
| MC1/Resources/Localization/es.lproj/Settings.strings | Adds localized “Text Size” strings (Spanish). |
| MC1/Resources/Localization/en.lproj/Settings.strings | Adds localized “Text Size” strings (English). |
| MC1/Resources/Localization/de.lproj/Settings.strings | Adds localized “Text Size” strings (German). |
| MC1/Resources/Generated/L10n.swift | Regenerates SwiftGen accessors for new localization keys. |
| MC1/MC1App.swift | Applies global UI scale and Dynamic Type behavior at the app root. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+15
to
+18
| /// `nil` means "defer to the system" — the value passed to `.dynamicTypeSize(_:)`. | ||
| /// `.system` maps to `nil` so the app keeps its current appearance: the root | ||
| /// override falls back to the `.large` preset, which `dynamicTypeSize(_:)` | ||
| /// treats as "no override" (no visual change for existing users). |
Comment on lines
93
to
+95
| .preferredColorScheme(appState.themeService.effectiveColorScheme) | ||
| .uiScale(appState.themeService.uiTextSizePreference.uiScale) | ||
| .environment(\.dynamicTypeSize, appState.themeService.uiTextSizePreference.dynamicTypeSize ?? .large) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a "Text Size" picker under Settings → Appearance with four presets (Default, Large, Extra Large, Extra Extra Large) that scales the whole app UI proportionally — useful on high-DPI displays (e.g. MacBook Retina via "Designed for iPad") and for users who want a bigger interface.
How it works
.dynamicTypeSizeenvironment override, which propagates to semantic fonts, SF Symbols, and@ScaledMetricvalues.\.dynamicTypeSizenor\.sizeCategoryscaleText/List), so a render-time zoom (UIScaleContainer) scales the whole window using the compensating-frame trick — layout is done atwindowSize / scale, then rendered atscale, keeping scroll metrics and hit targets consistent. No-op on iOS.@ScaledMetric(relativeTo: .body)so icons and spacing grow at the same rate as text. Safe by construction: at the default preset the scale is 1.0×, so there is zero visual change for existing users.Details
PersistenceKeys.appUITextSizePreference+BackupUserDefaultsmapping (backup/restore included), following the exactcolorSchemePreferencepattern (missing key →.systemwithout write-back; unknown raw value →.system+ corrective overwrite).Settings.Appearance.TextSize.*strings in all 10 languages;L10n.swiftregenerated via SwiftGen.ThemeServicetests covering default/unknown/refresh/restore paths and thedynamicTypeSize/uiScalemappings.Verification
xcodebuild buildpasses (iOS Simulator).Files changed (36)
MC1/Theme/AppUITextSizePreference.swift(new) — preference enum +dynamicTypeSize/uiScalemappingsMC1/Views/Components/UIScaleContainer.swift(new) — render zoom for MacMC1/Theme/ThemeService.swift— state + persistence + refreshMC1/MC1App.swift— root environment override + zoomMC1/Views/Appearance/AppearanceView.swift— Text Size picker@ScaledMetricconversionsMC1Services:PersistenceKeys+BackupUserDefaultsL10n.swiftMC1Tests/ThemeServiceTests.swiftTested on
Checklist
CONTRIBUTING.md