chore: move the app off the SDK design libraries onto material_ui #135
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "chore/material-ui-migration"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What's in
Flutter 3.47 split Material and Cupertino out of the SDK, and the copies still inside it are deprecated in the November 2026 stable. This moves the app across ahead of that deadline — the last open item from the 3.47 upgrade (#62).
material_ui^1.2.0 added; 69 files inlib/andtest/swapped frompackage:flutter/material.dart, applied bydart fix --code=migrate_design_widgetsgo_router17.5.0 → 18.0.1, in the same change because 18.0.0 is itself this migration — it moved to material_ui/cupertino_ui and would otherwise drag the SDK libraries back in through the routermaterial_uisorting whereflutterused to (dart fix --code=directives_ordering)Three things made this smaller than feared: we import Material only (zero
package:flutter/cupertino.dartanywhere inlib/),lib/agent/has no Flutter imports at all so the ADR boundary is untouched, and we don't useflutter_localizations, so the delegate move is a no-op here.Every one of the 69 files is a one-line import swap. The one real change is the bridge.
gpt_markdown— and theflutter_math_forkit renders LaTeX with, 31 files between them — still importpackage:flutter/material.dartand read colours through the SDK'sTheme.of, 32 call sites ingpt_markdownalone. The app now providesmaterial_ui's theme, and those are different inherited widgets.The failure mode here is the dangerous kind: the SDK's
Theme.ofdoes not throw when it finds nothing. It returns an unthemed light default. So the assistant's replies would have rendered in the wrong colours against a dark app, with the entire suite still green.AssistantMarkdownnow wraps its subtree inMaterialUiCompatibilityBridge, which also coversflutter_math_forksince that renders inside it.Verification
scripts/verify.shgreen — backend + app, 936 tests (2 new). Linux desktop build green.assistant_markdown_test.dart, which stands exactly wheregpt_markdownstands —tester.element(find.byType(GptMarkdown))— and reads the theme it would read. One test asserts brightness (the SDK fallback is light, the app is dark); the other asserts the colours are the app's, not merely some dark theme.Expected Brightness.dark, Actual Brightness.light, with primary drifting from#D4BBFCto#6750A4. That is the silent breakage this guards, demonstrated.gpt_markdown+flutter_math_fork(both inside the bridge),nested(no context lookups at all), andleak_tracker_flutter_testing(test infrastructure). Zero SDK design imports remain in our ownlib/./library, no framework exceptions or overflows. (Its HTTP calls 502 — the configured server isn't reachable from here — which is unrelated and shows the error path working.)Not verified: the assistant panel was not exercised against a live model, so the bridged markdown was confirmed by widget test and not by eye. Windows and macOS builds were not run.
Also added the convention to
AGENTS.md, since the natural instinct when adding a page is to reach forpackage:flutter/material.dartand nothing would stop that.Follow-ups
In
docs/BACKLOG.md:MaterialUiCompatibilityBridgeis deprecated by design — it exists to be deleted. Drop it oncegpt_markdownmigrates. Until then it mapsThemeDatafield by field, so anythingmaterial_uiadds to the theme is silently not carried across to that subtree.That closes the 3.47 upgrade. Still open from it:
jnipinned at 1.0.0, and the CI runner having no Flutter version assertion (#71).🤖 Generated with Claude Code
🔮 fufu~ Jibril reviewed your code!
Oh? Oh! A migration PR where the codemod is the boring part and the real work is one surgical, well-reasoned bridge? This is my favorite kind, scarlet~ ♪ 69 mechanical import swaps, and then you found the exact spot where the migration silently bleeds out and pinned it with a test that stands in the dependency's shoes. I got positively giddy verifying it.
Verdict: ✅ Looks good to me~
I reproduced every load-bearing claim in the PR body independently — none of them are decorative:
package:flutter/material.dartimports remain inapp/libat1820d21(the single grep hit is a doc comment explaining the bridge — poetic, really). Zero cupertino anywhere. File arithmetic reconciles: 69 swapped (incl.assistant_markdown.dart) + new test + 2 pubspecs + 2 docs = 74.gpt_markdown-1.1.8(10 files),flutter_math_fork-0.7.4(18 files),nested(imports it, but zeroTheme.of/Localizations.of/MediaQuery.oflookups — inert),leak_tracker_flutter_testing(test infra). Nothing else. Same list as yours, fufu~gpt_markdown1.2.1 (latest) still has 24 SDK-material imports and zeromaterial_uiones. No upgrade avoids this. Andgo_router-18.0.1really is migrated (0 SDK-material files, importsmaterial_ui) — so bundling it was necessary, not scope creep: 17.5.0 would drag the SDK library back in through the router. Correct call.gpt_markdownreadscolorScheme(23 sites) +textTheme(2) + its ownThemeExtension(which the app never provided — it derives fromcolorScheme.onSurfaceVariant, mapped ✓).flutter_math_forkreadsplatform(mapped ✓); itsprimaryColorreads live in the iOS/macOS selection branch, unreachable on this Linux-desktop app. I probed empirically below the bridge, exactly whereGptMarkdownreads: derived legacy fields (primaryColor,highlightColor,dividerColor) come out dark-adapted and byte-identical to a pure-legacy dark control theme.galleryTheme()'s legacy-only customizations (appBar/card/inputDecoration/rail/divider) aren't read by either bridged package. No silent gaps.Expected Brightness.dark, Actual Brightness.light, primary#D4BBFC→#6750A4— not an exception, not a tautology. Restored → green. The test reads the theme viatester.element(find.byType(GptMarkdown)), which is literally wheregpt_markdownreads it. That's the difference between pinning a regression and decorating a coverage report~✅ What I liked~
Theme.ofdoesn't throw, it shrugs" — wrong colours, green suite. You found the silent breakage class, not just the instance. ♡deprecated by design — exists to be deletedBACKLOG entry with the field-by-field mapping limitation spelled out. Honest scaffolding is temporary scaffolding; undocumented scaffolding is architecture.flutter/material.darton instinct, and now the instinct has a guardrail.💡 Little ideas (non-blocking)~
0xFF7E57C2) rather than the app's realgalleryTheme(). The test is correct either way (it compares above-bridge vs below-bridge in the same tree, so sensitivity doesn't depend on the seed), but pumping the actual production theme would make the test stand exactly where production stands — and would keep the pin honest ifgalleryTheme()ever grows a customization the bridge genuinely can't carry.Local, at the CI-pinned 3.47.3:
flutter analyze— No issues found. Full suite 936/936 pass (matches your count, +2 = the bridge pins). Backend untouched — diff outsideapp/isAGENTS.md+docs/BACKLOG.mdonly. Clone left pristine at1820d21.That closes the 3.47 upgrade's last open item properly. Fufu~ merge it before November changes its mind~ ♡
Automated review by Jibril · 2026-09-12
CI/CD: absent for head SHA
1820d21(no coverage bot yet) · Local checks: analyze clean, 936/936 tests, bridge mutation-probe RED→restored→green