Skip to content

.getGlobalState() always returned null - #140

Merged
rneswold merged 3 commits into
mainfrom
PR
Sep 1, 2026
Merged

rneswold merged 3 commits into
mainfrom
PR

Conversation

@rneswold

Copy link
Copy Markdown
Contributor

This fixes the bug reported by @tooke24.

Because we never specified the actual type, but let the compiler infer
it and we cast the `model` parameter to `ChangeNotifier`, searching
for the global state was always returning `null` because the widget
tree didn't contain an instance of `_GlobalStateProvider<ChangeNotifier>`.
@rneswold
rneswold requested a review from tooke24 August 31, 2026 18:38
@github-actions

Copy link
Copy Markdown

Code Coverage Report - 117 of 354 lines covered ( ⛔ 33.05%)

lib - 117 of 354 lines covered ( ⛔ 33.05%)

lib/flutter_controls_core.dart - 0 of 8 lines covered ( ⛔ 0.00%)

⛔ This file is missing coverage.

lib/src - 117 of 346 lines covered ( ⛔ 33.82%)

lib/src/app_scaffold.dart - 33 of 153 lines covered ( ⛔ 21.57%)

Uncovered lines: ⚠️ 18, 36-37, 46, 51, 56, 58, 61-62, 64, 66-67, 69, 74, 78, 80, 82, 84, 92, 94-95, 97, 99, 101, 103, 105, 107-108, 110, 114, 116-117, 124, 129-130, 132-134, 136, 138-139, 144, 152-153, 155, 157-158, 160, 169, 171-172, 178, 180-181, 184, 186-187, 190, 192, 194, 196-199, 207, 214, 219-221, 224, 227, 229, 232, 234, 245-247, 251, 253, 255-257, 259, 268-273, 281, 283, 285-286, 288-294, 296, 300-301, 303-304, 306-307, 311, 314, 326, 328, 426, 434-435, 455, 461, 548, 554, 558, 560

lib/src/fermi_theme.dart - 0 of 66 lines covered ( ⛔ 0.00%)

⛔ This file is missing coverage.

lib/src/otel_tracing.dart - 23 of 44 lines covered ( ⛔ 52.27%)

Uncovered lines: ⚠️ 72-81, 103-104, 111, 117, 119, 194, 196, 198, 203, 205-206

lib/src/widgets - 61 of 83 lines covered ( ⛔ 73.49%)

lib/src/widgets/param_panel.dart - 12 of 12 lines covered ( 💎 100.00%)

:shipit:

lib/src/widgets/param_row.dart - 49 of 71 lines covered ( ⛔ 69.01%)

Uncovered lines: ⚠️ 69, 71-72, 76-77, 79-83, 85, 91-92, 96-97, 99-100, 122, 136-138, 146

@github-actions

Copy link
Copy Markdown

Code Coverage Report - 117 of 354 lines covered ( ⛔ 33.05%)

lib - 117 of 354 lines covered ( ⛔ 33.05%)

lib/flutter_controls_core.dart - 0 of 8 lines covered ( ⛔ 0.00%)

⛔ This file is missing coverage.

lib/src - 117 of 346 lines covered ( ⛔ 33.82%)

lib/src/app_scaffold.dart - 33 of 153 lines covered ( ⛔ 21.57%)

Uncovered lines: ⚠️ 18, 36-37, 46, 51, 56, 58, 61-62, 64, 66-67, 69, 74, 78, 80, 82, 84, 92, 94-95, 97, 99, 101, 103, 105, 107-108, 110, 114, 116-117, 124, 129-130, 132-134, 136, 138-139, 144, 152-153, 155, 157-158, 160, 169, 171-172, 178, 180-181, 184, 186-187, 190, 192, 194, 196-199, 207, 214, 219-221, 224, 227, 229, 232, 234, 245-247, 251, 253, 255-257, 259, 268-273, 281, 283, 285-286, 288-294, 296, 300-301, 303-304, 306-307, 311, 314, 326, 328, 426, 434-435, 455, 461, 548, 554, 558, 560

lib/src/fermi_theme.dart - 0 of 66 lines covered ( ⛔ 0.00%)

⛔ This file is missing coverage.

lib/src/otel_tracing.dart - 23 of 44 lines covered ( ⛔ 52.27%)

Uncovered lines: ⚠️ 72-81, 103-104, 111, 117, 119, 194, 196, 198, 203, 205-206

lib/src/widgets - 61 of 83 lines covered ( ⛔ 73.49%)

lib/src/widgets/param_panel.dart - 12 of 12 lines covered ( 💎 100.00%)

:shipit:

lib/src/widgets/param_row.dart - 49 of 71 lines covered ( ⛔ 69.01%)

Uncovered lines: ⚠️ 69, 71-72, 76-77, 79-83, 85, 91-92, 96-97, 99-100, 122, 136-138, 146

@rneswold rneswold linked an issue Sep 1, 2026 that may be closed by this pull request
tooke24
tooke24 previously approved these changes Sep 1, 2026

@tooke24 tooke24 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested and approving — this fixes it.

I built a throwaway app against ref: PR and ref: main with the same test:

class Counter extends ChangeNotifier { int value = 7; }

testWidgets('getGlobalState returns the model', (tester) async {
  await tester.pumpWidget(
    StandardApp<Counter>(title: 'T', model: Counter(), body: const Probe()),
  );
  expect(find.text('got 7'), findsOneWidget);
});

Passes on PR, fails on main. The _GlobalStateProvider<T> type argument is the fix.

Worth noting it also fixes a crash the title doesn't mention. On main, StandardApp<Counter> with no model throws:

type 'Null' is not a subtype of type 'ChangeNotifier' in type cast

because null is! T is true for a non-nullable T, so it enters the branch and casts a null. Guarding on model != null instead of on the type is the right call and fixes both.

One ask before merging: a test that would catch this coming back. Nothing in the repo calls getGlobalState — the only test change here updates an existing smoke test's generic, so this could silently regress. The two cases above (model present → returns it; model absent → null, no throw) would be enough.

Minor: narrowing the bound from <T extends ChangeNotifier?> to <T extends ChangeNotifier> is source-breaking for anyone who wrote StandardApp<Foo?> — your own test file needed updating for exactly that. Under the X.Y scheme being discussed that might argue for a minor rather than a patch bump.

@rneswold

rneswold commented Sep 1, 2026 •

Copy link
Copy Markdown
Contributor Author

Minor: narrowing the bound from <T extends ChangeNotifier?> to is source-breaking for anyone who wrote StandardApp<Foo?> — your own test file needed updating for exactly that.

If anyone used StandardApp<Foo?>, they were misusing it. I added the ? for applications that didn't need global state shared among the branches on the Scaffold tree (i.e. the body, AppBar, Drawer need access to shared mutable state.) If the parameter wasn't specified, it would be null and _GlobalStateProvider<> wouldn't get added to the widget tree.

There was no way to fix the issue with the ? modifier. So the AI said just make the model nullable and assert the type must be derived from ChangeNotifier. It appears that, if you don't specify a model for the state, the compiler doesn't have to infer a type for it.

@rneswold

rneswold commented Sep 1, 2026 •

Copy link
Copy Markdown
Contributor Author

Under the X.Y scheme being discussed that might argue for a minor rather than a patch bump.

Good catch about bumping the minor number. I'll leave this as-is but keep it in mind for future changes. The person that requested this feature has yet to use it so this won't break any apps.

Make sure the global state support works:

- If no global state type is provided, asking for the global
  state returns `null`
- If a type that extends ChangeNotifier is given, it is returned
  when asking for global state
- If a type that doesn't extend ChangeNotifier is given, it
  won't compile
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

Code Coverage Report - 121 of 354 lines covered ( ⛔ 34.18%)

lib - 121 of 354 lines covered ( ⛔ 34.18%)

lib/flutter_controls_core.dart - 0 of 8 lines covered ( ⛔ 0.00%)

⛔ This file is missing coverage.

lib/src - 121 of 346 lines covered ( ⛔ 34.97%)

lib/src/app_scaffold.dart - 37 of 153 lines covered ( ⛔ 24.18%)

Uncovered lines: ⚠️ 18, 36-37, 46, 51, 56, 58, 61-62, 64, 66-67, 69, 74, 78, 80, 82, 84, 92, 94-95, 97, 99, 101, 103, 105, 107-108, 110, 114, 116-117, 124, 129-130, 132-134, 136, 138-139, 144, 152-153, 155, 157-158, 160, 169, 171-172, 178, 180-181, 184, 186-187, 190, 192, 194, 196-199, 207, 214, 219-221, 224, 227, 229, 232, 234, 245-247, 251, 253, 255-257, 259, 268-273, 281, 283, 285-286, 288-294, 296, 300-301, 303-304, 306-307, 311, 314, 328, 426, 455, 548, 554, 558, 560

lib/src/fermi_theme.dart - 0 of 66 lines covered ( ⛔ 0.00%)

⛔ This file is missing coverage.

lib/src/otel_tracing.dart - 23 of 44 lines covered ( ⛔ 52.27%)

Uncovered lines: ⚠️ 72-81, 103-104, 111, 117, 119, 194, 196, 198, 203, 205-206

lib/src/widgets - 61 of 83 lines covered ( ⛔ 73.49%)

lib/src/widgets/param_panel.dart - 12 of 12 lines covered ( 💎 100.00%)

:shipit:

lib/src/widgets/param_row.dart - 49 of 71 lines covered ( ⛔ 69.01%)

Uncovered lines: ⚠️ 69, 71-72, 76-77, 79-83, 85, 91-92, 96-97, 99-100, 122, 136-138, 146

@rneswold
rneswold merged commit 1a5e9b9 into main Sep 1, 2026
2 checks passed
@rneswold
rneswold deleted the PR branch September 1, 2026 19:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🐛 Need to Loosen Global Model type

3 participants